UniswapV4Router04 swap(bytes,uint256) Calldata-Offset Auth Bypass
Exploit Transactions
0xfe34c4beee447de536bbd3d613aa0e3aa7eeb63832e9453e4ef3999924ab466aVictim Addresses
0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675Ethereum0x00000000000044a361ae3cac094c9d1b14eece97EthereumLoss Breakdown
Similar Incidents
C87C Router tokenReceived Authentication Bypass Drains Victim-Approved USDT
37%0x7CAE Approved-Spender Drain
32%Dexible selfSwap allowance drain
31%TaraClient finalizeBlocks Quorum-Bypass via In-Tx Validator Set Mutation
31%CivTrade Fake-Pool Callback Drain
31%CauldronV4 solvency-check bypass enables uncollateralized MIM borrowing
30%Root Cause Analysis
UniswapV4Router04 swap(bytes,uint256) Calldata-Offset Auth Bypass
1. Incident Overview TL;DR
At Ethereum block 24575085, transaction 0xfe34c4beee447de536bbd3d613aa0e3aa7eeb63832e9453e4ef3999924ab466a exploited Uniswap v4 Router04 (0x00000000000044a361ae3cac094c9d1b14eece97) through malformed calldata passed to swap(bytes,uint256).
The adversary EOA 0xd6b7e831d64e573278f091aa7e68fbf2a8fa9916 called helper contract 0xded262d0a933b7bb4ed8c4b6cb2dce5b157b74a0, which issued a crafted router call that bypassed payer authentication and caused unauthorized spending from victim 0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675.
Incident outcome:
- Victim USDC debited:
42,606.959179 USDC(42606959179raw units, 6 decimals). - PoolManager USDC credited by the same amount.
- Gross ETH payout to adversary EOA:
21197984596759249607wei. - Gas paid:
9331433496067wei (210467 * 44336801). - Net adversary ETH delta:
+21197975265325753540wei (+21.197975265325753540 ETH).
Pre-state (sigma_B) required for exploit realization:
- Victim had positive USDC balance.
- Victim had non-zero USDC allowance to Router04.
- Router and PoolManager contracts were live on mainnet and callable permissionlessly.
The ACT sequence is a single adversary-crafted transaction and is inclusion-feasible without privileged access.
2. Key Background
UniswapV4Router04 supports a dynamic-argument entrypoint:
function swap(bytes calldata data, uint256 deadline) external payable returns (BalanceDelta);
data is expected to contain ABI-encoded BaseData plus swap path parameters. In callback handling, the decoded BaseData determines who is charged and who receives proceeds:
struct BaseData {
uint256 amount;
uint256 amountLimit;
address payer;
address receiver;
uint8 flags;
}
Relevant settlement behavior (Router callback path):
BaseData memory data = abi.decode(callbackData, (BaseData));
inputCurrency.settle(poolManager, data.payer, inputAmount, input6909);
outputCurrency.take(poolManager, data.receiver, outputAmount, output6909);
For ERC20 input (USDC here), settle(...) resolves to a transferFrom(payer, PoolManager, amount) flow, so correctness of data.payer authentication is safety-critical.
3. Vulnerability Analysis & Root Cause Summary
Root-cause category: ATTACK.
The vulnerable check in UniswapV4Router04.swap(bytes,uint256) authenticates caller identity using a fixed calldata position (calldataload(164)) instead of decoding BaseData.payer from the actual dynamic bytes location. ABI dynamic offsets are attacker-controlled; therefore a non-canonical but valid encoding can place attacker-controlled bytes at the fixed check location while keeping the decoded payer field set to a victim address.
In this incident, the attacker set the dynamic bytes offset to 0xc0, spoofed the fixed auth slot to the helper caller address, and retained victim as decoded payer in the payload. The auth check passed, then _unlockAndDecode consumed the decoded payload and charged the victim through token transfer settlement.
This violates the invariant that the authenticated payer used for settlement must equal the transaction caller for all accepted encodings. The concrete breakpoint is the assembly check:
assembly ("memory-safe") {
if iszero(eq(calldataload(164), caller())) {
mstore(0x00, 0x82b42900) // Unauthorized()
revert(0x1c, 0x04)
}
}
Security principles violated:
- Authentication must be bound to decoded semantic fields, not hard-coded calldata byte positions.
- If strict ABI shape is required, non-canonical encodings must be explicitly rejected.
4. Detailed Root Cause Analysis
Exploit mechanism (deterministic sequence):
- Entry transaction
- Sender:
0xd6b7e831d64e573278f091aa7e68fbf2a8fa9916. - Direct target: helper
0xded262d0a933b7bb4ed8c4b6cb2dce5b157b74a0. - Helper then called Router04
swap(bytes,uint256)(selector 0xaf2b4aba).
- Malformed calldata layout used to bypass auth
- Dynamic bytes offset word (
word[0]) was0xc0(non-canonical for a two-arg call). - Fixed auth-read slot (
word[5], absolute args byte offset 160) was set to helper caller address0xded262.... - Decoded payload fields still contained:
BaseData.payer(word[9]):0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675(victim).BaseData.receiver(word[10]):0xd6b7e831d64e573278f091aa7e68fbf2a8fa9916(adversary EOA).
Representative decoded words (from the router-call calldata inspection):
selector=af2b4aba
word[0] = ...000000c0
word[5] = ...ded262d0a933b7bb4ed8c4b6cb2dce5b157b74a0
word[9] = ...65a8f07bd9a8598e1b5b6c0a88f4779dbc077675
word[10] = ...d6b7e831d64e573278f091aa7e68fbf2a8fa9916
- Authorization bypass and semantic decode divergence
- Router auth check read
calldataload(164)and compared it tocaller(), which passed because the attacker controlled that absolute slot. - Router then executed
_unlockAndDecode(data), wheredataresolved from offset0xc0, not from fixed slot assumptions. - Callback logic used decoded
data.payer(victim) anddata.receiver(attacker EOA).
- Unauthorized spend and payout on-chain
- Trace evidence includes:
FiatTokenV2_2::transferFrom(
0x65A8F07Bd9A8598E1b5B6C0a88F4779DBC077675,
PoolManager: 0x000000000004444c5dc75cB358380D2e3dE08A90,
42606959179
)
PoolManager::take(
ETH,
0xd6B7e831D64e573278f091AA7E68Fbf2A8FA9916,
21197984596759249607
)
Gas used: 210467
- State-diff confirmation
- Victim USDC:
42606959179 -> 0(delta-42606959179). - PoolManager USDC: increased by
+42606959179. - Adversary EOA native balance: delta
+21197975265325753540wei (net after gas).
Exploit conditions (all satisfied in this incident):
- Victim holds positive USDC.
- Victim approved Router04 for USDC.
- Adversary can submit malformed calldata with fixed-slot spoof and dynamic payload victim payer.
5. Adversary Flow Analysis
Adversary strategy summary: one permissionless transaction using helper-crafted calldata to convert victim-approved USDC into attacker-received ETH.
Adversary-related accounts:
0xd6b7e831d64e573278f091aa7e68fbf2a8fa9916(EOA): tx sender and ETH profit recipient.0xded262d0a933b7bb4ed8c4b6cb2dce5b157b74a0(contract): direct Router caller and fixed-slot spoof value.
Victim candidates identified in analysis:
- USDC holder:
0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675(is_verified: unknown). - Router contract:
0x00000000000044a361ae3cac094c9d1b14eece97(is_verified: true).
Lifecycle stages:
- Stage 1 - Crafted entry transaction
Tx0xfe34...466ain block24575085: attacker EOA calls helper with victim/token targets. - Stage 2 - Auth bypass via malformed router calldata
Helper invokesswap(bytes,uint256)with offset/payload mismatch; fixed-slot auth passes while decoded payer is victim. - Stage 3 - Unauthorized spend and profit realization
Victim USDC is transferred to PoolManager and ETH is paid to attacker EOA.
This is ACT because execution required only public state, public interfaces, and standard transaction submission.
6. Impact & Losses
Measured losses and gains:
- Victim token loss:
42,606.959179 USDC. - Immediate attacker monetization: net
+21.197975265325753540 ETHafter gas.
Scope:
- Single observed exploit transaction in this case dataset.
- Directly affected party: victim USDC holder
0x65a8f07bd9a8598e1b5b6c0a88f4779dbc077675. - Protocol component involved in vulnerability: UniswapV4Router04 dynamic-bytes swap entrypoint.
Success predicate used for ACT validation:
- Profit predicate in ETH for adversary (
value_after - value_before - gas > 0) is satisfied with observed net delta.
7. References
Primary evidence:
- Transaction:
0xfe34c4beee447de536bbd3d613aa0e3aa7eeb63832e9453e4ef3999924ab466a(Ethereum mainnet, block24575085). - Seed metadata (tx envelope and calldata envelope).
- Verbose transaction trace (contains
transferFrom,PoolManager::take, gas used). - Balance diffs (native and ERC20 deltas for victim, pool manager, adversary).
- Router source (
UniswapV4Router04::swap(bytes,uint256)fixed-offset auth check). - Base router source (
BaseSwapRouter::_unlockCallbacksettlement and payout semantics). - Router calldata word decoding (
selector, dynamic offset, payer/receiver positions). - Call-tracer JSON (internal call graph and concrete calldata payloads).
Referenced contract/function identifiers:
- Router04:
0x00000000000044a361ae3cac094c9d1b14eece97,swap(bytes,uint256). - PoolManager:
0x000000000004444c5dc75cb358380d2e3de08a90,take(...). - USDC:
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48,transferFrom(...).