All incidents

Vault Spot-Price Execution Abuse

Share
Nov 10, 2025 14:14 UTCAttackLoss: 100,000 USDCPending manual check1 exploit txWindow: Atomic
Estimated Impact
100,000 USDC
Label
Attack
Exploit Tx
1
Addresses
1
Attack Window
Atomic
Nov 10, 2025 14:14 UTC → Nov 10, 2025 14:14 UTC

Exploit Transactions

TX 1Ethereum
0xe3eab35b288c086afa9b86a97ab93c7bb61d21b1951a156d2a8f6f5d5715c475
Nov 10, 2025 14:14 UTCExplorer

Victim Addresses

0x6a06707ab339bee00c6663db17ddb422301ff5e8Ethereum

Loss Breakdown

100,000USDC

Similar Incidents

Root Cause Analysis

Vault Spot-Price Execution Abuse

1. Incident Overview TL;DR

At Ethereum block 23769387, an attacker exploited the unverified vault at 0x6a06707ab339bee00c6663db17ddb422301ff5e8 after a depositor had already loaded 100,000 USDC into it. The attacker used a flash loan to push the configured Uniswap V3 USDC/WETH pool at 0xe0554a476a092703abdb3ef35c80e0d76d32939f to an artificial price, then called the vault’s public swapToWETH(uint256) path. The vault sold the full deposited USDC against that manipulated pool state and received only 120518513556060 raw WETH units, while the attacker unwound the manipulation, repaid borrowed liquidity, paid the block fee recipient, and retained 26108706358189380348 wei of net ETH.

The root cause is that deposit authorization and execution authorization were separated, while execution safety depended on a live spot quote from the same pool being traded. Any unprivileged actor who could move the configured pool price could trigger the victim sale at that manipulated quote.

2. Key Background

The victim vault is a thin wrapper contract. Its runtime bytecode forwards every call by DELEGATECALL into implementation 0x8aa6b0e10bd6dbaf5159967f92f2e740afe2b4c3, so all user-visible vault behavior is implemented there.

PUSH20 8aa6b0e10bd6dbaf5159967f92f2e740afe2b4c3
GAS
DELEGATECALL

Origin: victim vault runtime disassembly.

Before exploitation, the vault storage already contained the depositor address in slot 1, the Uniswap QuoterV2 in slot 3, SwapRouter02 in slot 4, the Uniswap V3 factory in slot 5, WETH in slot 6, and USDC in slot 10. The deposit transaction 0xba58ad38b66ecdc999599db83011d72d9248ec42189006332a941317919ee1e5 moved 100000000000 raw USDC units from depositor 0x76d6f63a7e2d8202d3534d836c2e724be74e965b into the vault and emitted the vault’s TokensDeposited event.

The quick deposit trace also shows the only observed depositor-specific guard: the implementation loads slot 1 and compares it with CALLER during deposite(uint256). That guard is relevant because the exploit later succeeds from a different caller.

3. Vulnerability Analysis & Root Cause Summary

This is an ATTACK-class ACT vulnerability. The vault let a third party execute a previously funded USDC-to-WETH conversion using a manipulable spot quote taken from the exact pool used for settlement. The design did not bind the order to a depositor-committed amountOutMinimum, a TWAP, or any other manipulation-resistant price bound.

The invariant should have been: deposited USDC may only be swapped when the execution price satisfies a condition authorized by the depositor, not merely a condition observable after an attacker moves pool state. The implementation breakpoint is the swapToWETH(uint256) path in the delegatecall target. In the exploit trace, that path first queries QuoterV2::quoteExactInputSingle on the configured USDC/WETH pool and then immediately passes the resulting manipulated quote into SwapRouter02::exactInputSingle as the effective execution floor.

Because execution remained permissionless, the attacker could deterministically compose public flash liquidity, a temporary pool distortion, the victim vault call, and a same-transaction unwind. No privileged keys, private calldata, or attacker-only contract rights were required.

4. Detailed Root Cause Analysis

The funding step is established by the deposit receipt and quick trace notes. The depositor transferred 100000000000 raw USDC units into the vault, and the delegatecall path enforced that slot 1 matched the depositor during deposite(uint256).

{
  "key_observations": [
    "0x6a06707ab339bee00c6663db17ddb422301ff5e8 immediately delegatecalls into 0x8aa6b0e10bd6dbaf5159967f92f2e740afe2b4c3 for deposite(uint256).",
    "The delegatecall path loads slot 1 and compares it to CALLER; in this tx slot 1 equals depositor 0x76d6f63a7e2d8202d3534d836c2e724be74e965b, so the guard passes.",
    "The deposit flow emits an ERC20 Transfer of 100000000000 USDC from 0x76d6... to 0x6a06... and emits TokensDeposited(user, token, amount)."
  ]
}

Origin: deposit trace notes.

At block 23769386, the vault state already pointed to the Uniswap execution stack needed for the later sale:

{
  "slot_3": "0x61ffe014ba17989e743c5f6cb21bf9697530b21e",
  "slot_4": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
  "slot_5": "0x1f98431c8ad98523631ae4a59f267346ea31f984",
  "slot_6": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
  "slot_10": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
}

Origin: vault storage interpretation before the exploit block.

The exploit transaction 0xe3eab35b288c086afa9b86a97ab93c7bb61d21b1951a156d2a8f6f5d5715c475 then shows the decisive sequence. The attacker-controlled contract invoked swapToWETH(100000000000) on the vault after first moving the pool price. Inside the vault execution path, the trace records the live quote and immediate swap:

0x6A06707ab339BEE00C6663db17DdB422301ff5e8::swapToWETH(100000000000)
0x8aA6B0E10BD6DBaf5159967F92f2E740afE2b4C3::swapToWETH(100000000000) [delegatecall]
QuoterV2::quoteExactInputSingle(... amountIn: 100000000000, fee: 100 ...)
0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45::exactInputSingle(
  tokenIn=USDC,
  tokenOut=WETH,
  fee=100,
  recipient=0x6A06707ab339BEE00C6663db17DdB422301ff5e8,
  amountIn=100000000000,
  amountOutMinimum=119915920988279
)

Origin: exploit transaction trace.

That behavior confirms the breakpoint described in the root-cause JSON: the execution guard is not an external invariant, it is a quote derived from attacker-controlled spot state. The exploit receipt and balance diff show the resulting state change. The vault’s USDC balance fell from 100000000000 to 0, the pool’s USDC balance increased by 100000000001, and the vault received only 120518513556060 raw WETH units. The attacker EOA’s native balance increased by 26108706358189380348 wei, while 995375203980555664 wei went to block fee recipient 0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97.

5. Adversary Flow Analysis

The adversary flow is a single-transaction flash-loan manipulation followed by permissionless victim execution and unwind.

  1. The attacker EOA 0xc0ffeebabe5d496b2dde509f9fa189c25cf29671 submitted transaction 0xe3eab35b288c086afa9b86a97ab93c7bb61d21b1951a156d2a8f6f5d5715c475 to attacker contract 0xe08d97e151473a848c3d9ca3f323cb720472d015.
  2. The attacker contract obtained 13,980,773 USDC of flash liquidity and used it to buy WETH in the configured USDC/WETH pool, pushing the pool to a distorted price.
  3. While the pool remained manipulated, the attacker called the vault’s public swapToWETH(100000000000) function. The vault itself queried QuoterV2 and then routed the victim’s full USDC balance through SwapRouter02 at the manipulated price.
  4. The attacker then sold WETH back, repaid the flash liquidity, paid the block builder fee, and kept the residual value.

The exploit is ACT because each step relies only on public contracts and public market state: flash liquidity, a permissionless pool, and a permissionless victim execution path.

6. Impact & Losses

The measurable vault-side loss is the full 100000000000 raw USDC units that had been deposited by the victim user. In return, the vault received only 120518513556060 raw WETH units, far below the honest pre-manipulation quote for the same notional size.

The attacker captured the value difference. The balance-diff artifact records 26108706358189380348 wei of native-balance gain for the attacker EOA after the transaction, with fees separately attributable to gas and the direct builder payment.

7. References

  • Deposit transaction: 0xba58ad38b66ecdc999599db83011d72d9248ec42189006332a941317919ee1e5
  • Exploit transaction: 0xe3eab35b288c086afa9b86a97ab93c7bb61d21b1951a156d2a8f6f5d5715c475
  • Victim vault: 0x6a06707ab339bee00c6663db17ddb422301ff5e8
  • Delegatecall implementation: 0x8aa6b0e10bd6dbaf5159967f92f2e740afe2b4c3
  • Uniswap V3 pool: 0xe0554a476a092703abdb3ef35c80e0d76d32939f
  • QuoterV2: 0x61fFE014bA17989E743c5F6cB21bF9697530B21e
  • SwapRouter02: 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
  • Balance-diff evidence: attacker EOA profit and vault drain in the exploit balance diff artifact
  • Fee-recipient identification: block 23769387 miner/fee-recipient artifact for 0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97