All incidents

Size GenericRoute Approval Drain

Share
Aug 15, 2025 10:09 UTCAttackLoss: 20,000 PT-wstUSR-25SEP2025Pending manual check3 exploit txWindow: 4m 48s
Estimated Impact
20,000 PT-wstUSR-25SEP2025
Label
Attack
Exploit Tx
3
Addresses
2
Attack Window
4m 48s
Aug 15, 2025 10:09 UTC → Aug 15, 2025 10:14 UTC

Exploit Transactions

TX 1Ethereum
0x17846acccd832432dba32bf1008797377324a1bd8bd8ef8e52ec8171afc99a81
Aug 15, 2025 10:09 UTCExplorer
TX 2Ethereum
0xc7477d6a5c63b04d37a39038a28b4cbaa06beb167e390d55ad4a421dbe4067f8
Aug 15, 2025 10:13 UTCExplorer
TX 3Ethereum
0x23ccb2f1dc6700c2f077bb400fb84dbf4d786390fe8fba6a5e4e1c1864221ace
Aug 15, 2025 10:14 UTCExplorer

Victim Addresses

0xf4a21ac7e51d17a0e1c8b59f7a98bb7a97806f14Ethereum
0x83eccb05386b2d10d05e1baea8ac89b5b7ea8290Ethereum

Loss Breakdown

20,000PT-wstUSR-25SEP2025

Similar Incidents

Root Cause Analysis

Size GenericRoute Approval Drain

1. Incident Overview TL;DR

An unprivileged adversary used Size's public LeverageUp zap at 0xF4a21Ac7e51d17A0e1C8B59f7a98bb7A97806f14 to drain 20000 PT-wstUSR-25SEP2025 from tradcorp.eth (0x83eCCb05386B2d10D05e1BaEa8aC89b5B7EA8290). The attacker deployed a helper contract, initialized it, invoked LeverageUp through the helper, and then withdrew the stolen PT balance. The loss did not require protocol ownership, compromised keys, or privileged roles.

The root cause is that LeverageUp exposes DexSwap._swapGenericRoute to public callers and that branch performs an unrestricted external call with attacker-chosen target and calldata. That breaks the invariant that zap routing should only perform authentic swaps over zap-controlled funds. In the exploit trace, LeverageUp first observes the victim's standing PT allowance and then executes PendlePrincipalToken::transferFrom(victim, helper, 20000000000000000000000), turning the victim's prior approval into an unauthorized transfer primitive.

2. Key Background

Size's LeverageUp flow accepts a caller-supplied market address plus an array of swap route descriptions. One supported route type is GenericRoute, intended to let the zap call an arbitrary router while preparing leverage operations. PT-wstUSR-25SEP2025 at 0x23E60d1488525bf4685f53b3aa8E676c30321066 is a Pendle principal token with standard ERC20 allowance semantics.

That combination is dangerous when the zap itself is the approved spender. If a victim has already approved the zap, and the zap lets public callers convert route data into arbitrary low-level calls, the zap can be tricked into spending that approval outside any legitimate market action. The collected helper analysis shows the attacker used a purpose-built fake market contract that returns plausible values for riskConfig, data, oracle, deposit, and ERC20-like helper methods so that LeverageUp's interface checks succeed.

3. Vulnerability Analysis & Root Cause Summary

This is an ATTACK-category ACT incident caused by an arbitrary-call surface inside a public approval-bearing zap. The critical issue is not a broken Pendle token invariant; it is Size's decision to let user-controlled GenericRoute data determine both the callee and calldata of a raw external call. In DexSwap._swapGenericRoute, the zap grants an approval to the supplied router and then executes (bool success,) = params.router.call(params.data); without authenticating the router, selector, recipient, token source, or linkage to a valid Size market. LeverageUp.leverageUpWithSwap exposes this path directly to public callers through SwapParams[].

The exploit combines two ingredients. First, the victim had already granted LeverageUp a standing PT allowance of exactly 20000000000000000000000. Second, the attacker supplied a fake market contract that satisfied LeverageUp's read-only checks while packaging GenericRoute(router = ptToken, tokenIn = helper, data = abi.encodeWithSelector(transferFrom, victim, helper, 20000e18)). When LeverageUp processed that route, it invoked the PT token directly and spent the victim's allowance in favor of the attacker-controlled helper.

4. Detailed Root Cause Analysis

The relevant protocol invariant is straightforward: a leverage zap may route swaps over assets it legitimately controls for the current user flow, but it must never expose a generic path that can trigger unrelated external effects using third-party approvals. The code-level breakpoint is the GenericRoute execution site in Size's zap logic:

(bool success,) = params.router.call(params.data);

The incident's pre-state is Ethereum mainnet immediately before block 23145764, after the victim already held PT-wstUSR-25SEP2025 and had already approved LeverageUp for 20000e18 PT. The attacker then used a four-transaction sequence:

  1. 0x17846acccd832432dba32bf1008797377324a1bd8bd8ef8e52ec8171afc99a81 deployed helper 0xa6dc1fc33c03513a762cdf2810f163b9b0fd3a71.
  2. 0xda91d19080f799f609eb5c513439945afce65601caa066e32098efd32fbeb1b9 initialized the helper.
  3. 0xc7477d6a5c63b04d37a39038a28b4cbaa06beb167e390d55ad4a421dbe4067f8 executed the exploit through LeverageUp.
  4. 0x23ccb2f1dc6700c2f077bb400fb84dbf4d786390fe8fba6a5e4e1c1864221ace withdrew the stolen PT from the helper.

The trace for the exploit transaction shows the semantic breakpoint directly:

PendlePrincipalToken::allowance(
  0x83eCCb05386B2d10D05e1BaEa8aC89b5B7EA8290,
  0xF4a21Ac7e51d17A0e1C8B59f7a98bb7A97806f14
) = 20000000000000000000000

PendlePrincipalToken::transferFrom(
  0x83eCCb05386B2d10D05e1BaEa8aC89b5B7EA8290,
  0xA6dc1FC33C03513A762cdf2810f163B9B0FD3a71,
  20000000000000000000000
)

The helper analysis explains why the fake market was sufficient. Its data() function embeds the PT token and current contract address, riskConfig() returns permissive values, deposit() is a no-op, and ERC20-like methods such as allowance, balanceOf, approve, and transferFrom return values that allow LeverageUp to continue execution. That means LeverageUp never authenticates the market argument and never binds GenericRoute to a legitimate swap.

5. Adversary Flow Analysis

The adversary cluster consists of EOA 0xa7e9b982b0e19a399bc737ca5346ef0ef12046da and helper contract 0xa6dc1fc33c03513a762cdf2810f163b9b0fd3a71. The deployment tx created the helper; the initialization tx enabled its owner-gated entrypoint; the exploit tx made the helper call LeverageUp; and the final tx swept the stolen PT back to the EOA.

At a high level, the helper wrapped a call into LeverageUp.leverageUpWithSwap and supplied attacker-controlled SwapParams. The helper advertised itself as a market-like contract by exposing the functions LeverageUp expected to call. Inside the exploit path, the attacker chose GenericRoute and encoded a PT transferFrom instead of a legitimate swap. Because the victim had already approved LeverageUp, the zap itself became the authorized spender and executed the transfer on the victim's behalf.

The helper then held the stolen PT until the attacker called its withdrawal routine. The collected helper behavior summary shows an owner-only withdrawERC20(address[]) routine that transfers each token balance to the stored owner. That closes the loop from arbitrary external call, to victim token loss, to attacker-controlled asset realization.

6. Impact & Losses

The measurable loss is the direct theft of 20000 PT-wstUSR-25SEP2025 from tradcorp.eth. In smallest units, the loss is 20000000000000000000000 with 18 decimals. The transfer path is not an accounting artifact or valuation estimate; it is a concrete unauthorized ERC20 transfer backed by the victim's existing approval to the Size zap.

The exploit conditions are also clear. A victim must have granted LeverageUp token allowance, the attacker must be able to submit GenericRoute data to the public zap, and the attacker must choose calldata that converts the zap's spender privilege into a third-party transfer. All three conditions are satisfied in the recorded exploit.

7. References

  • Exploit trace: 0xc7477d6a5c63b04d37a39038a28b4cbaa06beb167e390d55ad4a421dbe4067f8
  • Helper deployment tx: 0x17846acccd832432dba32bf1008797377324a1bd8bd8ef8e52ec8171afc99a81
  • Helper withdrawal tx: 0x23ccb2f1dc6700c2f077bb400fb84dbf4d786390fe8fba6a5e4e1c1864221ace
  • Size LeverageUp / DexSwap contract: 0xF4a21Ac7e51d17A0e1C8B59f7a98bb7A97806f14
  • Victim address: 0x83eCCb05386B2d10D05e1BaEa8aC89b5B7EA8290
  • Token address: 0x23E60d1488525bf4685f53b3aa8E676c30321066
  • Helper contract analysis and selector map for 0xa6dc1fc33c03513a762cdf2810f163b9b0fd3a71