All incidents

Public weETH Drain

Share
Jul 05, 2025 21:03 UTCAttackLoss: 106.93 weETHPending manual check1 exploit txWindow: Atomic
Estimated Impact
106.93 weETH
Label
Attack
Exploit Tx
1
Addresses
1
Attack Window
Atomic
Jul 05, 2025 21:03 UTC → Jul 05, 2025 21:03 UTC

Exploit Transactions

TX 1Ethereum
0xa57ec56af91ec70517ca71ca50101958d9c2ec9fdb61edcf35a9081c375725c2
Jul 05, 2025 21:03 UTCExplorer

Victim Addresses

0x54cd23460df45559fd5feeaada7ba25f89c13525Ethereum

Loss Breakdown

106.93weETH

Similar Incidents

Root Cause Analysis

Public weETH Drain

1. Incident Overview TL;DR

The incident is a one-transaction anyone-can-take drain of proxy 0x54cd23460df45559fd5feeaada7ba25f89c13525 on Ethereum block 22855569. The attacker EOA 0xb750e3165de458eae09904cc7fad099632860b0f used helper contract 0x1a61249f6f4f9813c55aa3b02c69438607272ed3 to call selector 0x03b79c24(address) through the proxy, receive the proxy's full weETH balance, swap it through Uniswap V3 pool 0x202a6012894ae5c288ea824cbc8a9bfb26a49b93, unwrap the resulting WETH, and finish with 114513358626551404812 wei of net ETH profit after gas.

The root cause is not a pricing issue or privileged access path. The proxy delegates to implementation 0xbc4b1d58b28c497b7afda6fb90fe1471fa0672cc, and that implementation exposes selector 0x03b79c24(address) as a permissionless full-balance transfer of the proxy's weETH holdings to any caller-chosen recipient.

2. Key Background

The victim is a proxy that held weETH at the moment immediately before block 22855569. On-chain storage confirms that slot 3 of proxy 0x54cd... contains token address 0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee, which is weETH, and the EIP-1967 implementation slot points to 0xbc4b1d58b28c497b7afda6fb90fe1471fa0672cc.

The exploit was transaction index 0 in block 22855569, so the attacker did not need a same-block setup from another participant. The pre-state already contained 106929468097270451433 wei of weETH on the proxy, and the weETH/WETH Uniswap V3 pool already held enough WETH liquidity to monetize the drain immediately.

Proxy implementation slot:
0x000000000000000000000000bc4b1d58b28c497b7afda6fb90fe1471fa0672cc

Proxy slot 3:
0x000000000000000000000000cd5fe23c85820f7b72d0926fc9b05b43e359b7ee

3. Vulnerability Analysis & Root Cause Summary

This is an access-control failure on an asset-moving function. The intended invariant is straightforward: only an authorized controller should be able to move weETH held by proxy 0x54cd..., and arbitrary callers must never be able to redirect those assets. That invariant is broken in implementation 0xbc4b... on selector 0x03b79c24(address).

The exploit path is concrete in both on-chain state and execution traces. The implementation selector reads the token address from proxy storage slot 3, measures balanceOf(address(this)), and then performs an ERC20 transfer(recipient, fullBalance) using the caller-supplied recipient. No authorization check appears before the transfer in the executed path. Because the call is reachable through the public proxy fallback, any unprivileged caller can sweep the proxy's entire weETH balance whenever that balance is positive.

4. Detailed Root Cause Analysis

The exploit transaction 0xa57ec56af91ec70517ca71ca50101958d9c2ec9fdb61edcf35a9081c375725c2 was sent by attacker EOA 0xb750... to helper contract 0x1a61.... Inside that transaction, the helper called the victim proxy with calldata starting with selector 0x03b79c24 and with its own address as the recipient argument.

The trace shows the proxy delegating the call into implementation 0xbc4b..., then querying the proxy's current weETH balance, and then transferring the entire amount to the helper:

victim_proxy::fallback(0x03b79c24...)
  0xBc4b1D58...::03b79c24(...) [delegatecall]
    WeETH::balanceOf(victim_proxy) -> 106929468097270451433
    WeETH::transfer(ExploitExecutor, 106929468097270451433)
    Transfer(from: victim_proxy, to: ExploitExecutor, value: 106929468097270451433)

The balance diff independently confirms the same drain outcome: proxy 0x54cd... lost exactly 106929468097270451433 wei of weETH, and the Uniswap V3 pool gained the same amount. This is consistent with a full-balance sweep followed by immediate monetization rather than partial theft or accounting drift.

The code-level breakpoint can therefore be stated precisely: selector 0x03b79c24(address) in implementation 0xbc4b... performs balanceOf(address(this)) and transfer(recipient, fullBalance) against the token stored in slot 3, but does not gate the operation on msg.sender or any role-bearing storage. As long as the proxy still routes that selector and holds weETH, the drain remains permissionless and repeatable.

5. Adversary Flow Analysis

The attacker flow is short and fully on-chain.

  1. The attacker EOA 0xb750... submitted one transaction to helper 0x1a61....
  2. The helper invoked selector 0x03b79c24(address) on proxy 0x54cd..., passing itself as recipient.
  3. The proxy delegated to implementation 0xbc4b..., which transferred all 106929468097270451433 wei of weETH from the proxy to the helper.
  4. The helper sold the stolen weETH into Uniswap V3 pool 0x202a... and received 114534059890882021484 wei of WETH.
  5. The helper unwrapped WETH to ETH and forwarded the ETH to the attacker EOA.
Swap(sender: ExploitExecutor, recipient: ExploitExecutor,
     amount0: -114534059890882021484,
     amount1: 106929468097270451433)

Withdrawal(src: ExploitExecutor, wad: 114534059890882021484)

The attacker did not rely on privileged keys, private orderflow, or protocol-admin actions. The only prerequisites were a positive proxy weETH balance and publicly available swap liquidity.

6. Impact & Losses

The direct victim loss was the proxy's entire recorded weETH inventory at exploit time:

{
  "token_symbol": "weETH",
  "amount": "106929468097270451433",
  "decimal": 18
}

The attacker monetized that inventory into 114534059890882021484 wei of WETH, then into ETH, and after gas finished with 114513358626551404812 wei more ETH than before the transaction. The affected party is the proxy vault at 0x54cd23460df45559fd5feeaada7ba25f89c13525, whose custody invariant over weETH was completely broken.

7. References

  1. Exploit transaction: 0xa57ec56af91ec70517ca71ca50101958d9c2ec9fdb61edcf35a9081c375725c2
  2. Victim proxy: 0x54cd23460df45559fd5feeaada7ba25f89c13525
  3. Proxy implementation: 0xbc4b1d58b28c497b7afda6fb90fe1471fa0672cc
  4. Token drained from the proxy: 0xcd5fe23c85820f7b72d0926fc9b05b43e359b7ee (weETH)
  5. Monetization pool: 0x202a6012894ae5c288ea824cbc8a9bfb26a49b93
  6. Evidence used: seed transaction metadata, seed trace, seed balance diff, proxy storage inspection, and the validated Foundry reproduction flow