Security · Analysis
Ether.fi's Old Queue Could Only Rob Smart Wallets
An attacker used a 2024 withdrawal queue to spend other people's token approvals. The plain wallets holding the most were out of reach. The eleven that were drained all carry code, and nine of them run Coinbase Smart Wallet's implementation.
At 07:20:11 UTC on September 11, a wallet that had never sent a transaction deployed a contract that pulled tokens out of eleven other wallets in one go. The losses were small: 14.45 liquidETH and 7.05 USDC, which the attacker swapped for about 15.45 ETH. The Crypto Times reported that ether.fi chief executive Mike Silagadze traced the loss to an old Veda contract a small number of users had approved, and pledged that affected users would be repaid.
What the coverage didn't explain is who got hit. The same transaction logs show wallets with far larger approvals left alone. That wasn't restraint. The contract physically could not reach them. Every wallet it could reach carries code, and most of them are the upgraded "smart" accounts that EIP-7702 was built to create.
A solver nobody checked
The contract is an AtomicQueue, written by Veda and deployed on March 16, 2024. Etherscan labels it "ether.fi: Withdrawal Queue." Users approved it to take their liquidETH vault shares, and "solvers" filled their exit requests. This desk read the verified source. Its solve() function takes a solver address as an argument and never checks it against the caller. It then does two things with that address. It calls finishSolve() on it, and it runs want.safeTransferFrom(solver, user, amount), pulling the "want" token out of the solver's wallet under whatever approval the solver has given the queue.
That was enough. The attacker's contract opened requests in its own name, offering a worthless token and asking for liquidETH or USDC. Then it called solve() and named each victim as the solver. The queue pulled each victim's tokens and handed them to the attacker. The contract has no owner and no pause function, so it can't be switched off. The only fix is for users to revoke their approvals.
Why plain wallets were safe
The finishSolve() step is what picked the victims. In Solidity, a call like that fails if the target address has no code. Ordinary wallets, the kind controlled by a single private key, have none. So naming one as the solver would have reverted the whole transaction.
This desk checked every drained address on-chain as of the exploit block. All eleven have code. Seven are EIP-7702 accounts: ordinary wallets that have delegated to smart-contract code, a feature that arrived with Ethereum's Pectra upgrade in May 2025. Six of those seven delegate to EIP7702Proxy, the proxy Coinbase Smart Wallet uses for upgrades, and their implementation slot points to the Coinbase Smart Wallet contract. The seventh is an Ambire 7702 account. Three more are standard Coinbase Smart Wallet contract accounts, whose proxies point at the same implementation. The last is a small 230-byte contract this desk could not identify.
Where the 14.45 drained liquidETH came from
Coinbase's wallet did nothing wrong here. Its implementation inherits Solady's Receiver, a fallback that answers the standard NFT-receipt callbacks and quietly accepts any other call it doesn't recognize. That's a common, defensible design, since smart accounts are supposed to accept incoming calls. It also means an unexpected finishSolve() succeeds instead of reverting. The flaw is the queue's. Whether a victim could be reached came down to what their wallet did with a call it didn't expect.
The chain shows the difference directly. At the exploit block, a plain wallet (0x0a807c…) held 300.79 liquidETH and a 482-liquidETH allowance to the queue. This desk confirmed both figures. The attacker never touched it. It did drain an Ambire account holding 0.000558 liquidETH. The largest victim, a Coinbase Smart Wallet 7702 account that lost 12.37 liquidETH, first approved the queue on July 5, 2024, ten months before EIP-7702 existed on mainnet. It refreshed that approval in July 2025. The chain doesn't directly show when the account itself was upgraded, and this desk isn't claiming the upgrade came after the approval.
Repaid before most people read about it
According to The Crypto Times, the first public alert came from ExVul at 07:51 UTC, 31 minutes after the drain, and the proceeds went through Tornado Cash in eleven deposits. The attacker's wallet has sent exactly twelve transactions, consistent with one exploit and eleven deposits. Then, at 16:28 UTC and again at 16:35 UTC, a Gnosis Safe at 0xf6c612… sent tokens back to the victims. This desk confirmed that both transactions succeeded. The independent reconstruction lists a third and matches all eleven repayments to within dust. The Safe carries no public ether.fi label, so the link rests on timing, exact amounts and the pledge.
The dollar figure depends on who you ask. The Crypto Times put the loss near $38,000 at $2,470 per ETH. DefiLlama's feed records $43,260. The GitHub reconstruction argues the lower figure is right, based on DefiLlama's own ETH price for that minute. Either way, this is a five-figure incident.
The exposure that remains
The same reconstruction counted 1,983 addresses that, a day after the attack, still had both a liquidETH balance and a live approval to the queue. Together that's up to 961 liquidETH. Only 243 of them have code, and 231 of those are 7702 accounts. By its estimate, at most about 19 liquidETH is reachable through this path today. This desk has not rerun that scan.
One correction to that work. Its summary says nine of the eleven victims are EIP-7702 accounts, but its own per-wallet table lists seven, which matches this desk's reading. The count that does come to nine is a different one: nine of the eleven victims run Coinbase Smart Wallet code, six of them through 7702 and three as ordinary contract accounts.
The Take
The reason most approvers kept their tokens wasn't a security check. It was an accident: a callback that happens to fail against an address with no code. EIP-7702 is taking that accident away one wallet at a time, which is the point of it. Smart accounts are meant to accept calls, and a fallback that says yes to anything is reasonable. But every approval signed back when a wallet was "just a key" was made on assumptions that no longer hold once the wallet grows code. The risk is small in this case: an immutable queue, about 19 liquidETH left in reach, victims repaid within nine hours. The pattern isn't small. Before upgrading a wallet, or letting an app upgrade it for you, clear out old approvals. Protocols retiring a contract should tell approvers to revoke, not just stop pointing the front end at it.