Decurity Research

Not Every Drain Is Atomic.

How much could have been saved after the first transaction?

Over $2.5M rescued by Defimon, our real-time threat detection and prevention bot built by Decurity.

To understand how much more could have been saved, we reconstructed per-tx drain timelines for 10 selected DeFi exploits from on-chain data — cases where the attack ran across multiple transactions, leaving a window for rescue.

scroll to explore ↓
The dataset · ten exploits, 2022–2026

Drains, by the minute

Each cell is one exploit's drain curve, reconstructed from on-chain data. The dataset spans bridges, lending markets, AMMs and cross-chain routers, $500K to $190M in losses — picked because each one had a window, however brief, between the first attacker tx and the last.

Squid Router opens the set. It's not an "ideal case" — it's a small one ($623K), where the attacker happened to be a bot and the rescue infrastructure happened to be ready. Conditions like that don't repeat reliably. It's a useful starting point because the moving parts are visible; the other nine show what happens when the parts don't line up the same way.

Squid Router Apr 7, 2026 ✓ Defimon rescued
Protocol background

Squid Router multicall · permissionless run()

Squid Router is a cross-chain swap aggregator. Its SquidMulticall contract — deployed at the same address on Arbitrum, BSC, Avalanche, Optimism, and Base — exposes a run() function that executes an arbitrary list of external calls with no access control. Anyone can call it. Anyone can pass any payload.

This is fine as long as the contract has no allowances of its own. The risk surface appears the moment a user approves tokens directly to SquidMulticall instead of to the Squid router proper — at which point any caller can pass a transferFrom payload through run() and pull the user's tokens out.

09:41 UTC — MEV bot finds the approval

A bot drains 1 WETH

A wallet at 0xaCc0…0E98 had granted infinite approvals to SquidMulticall across multiple chains — approximately $623K worth of tokens reachable through those allowances. It was an operational mistake: the approvals were supposed to go to the Squid router address, not the multicall. The wallet repeated the mistake on each chain it used Squid on.

At 09:41:40 UTC, an MEV bot calls run() on BSC with a crafted Call struct containing a transferFrom against the WETH contract — and pulls 1 WETH out of the victim's wallet. Roughly $2,400.

09:45 UTC — Whitehat bot engages

Front-running the remaining approvals

Our whitehat bot Defimon picks up the first attack within four minutes. There's no admin to contact and no pause to trigger; the contract is doing exactly what its code allows. The only working response is the same one the attacker used: call run() with crafted payloads, but route the tokens to a custody address we control.

Defimon enumerates the victim's exposed approvals across all five chains and submits rescue transactions on each. The first lands at 09:45 — $119K out of the attack path. Four more follow at 09:48:38 through 09:48:57.

09:49 UTC — End of window

$512K rescued

Five whitehat transactions in total. The MEV bot made no further moves — it kept the initial 1 WETH (~$2,400); Defimon caught the remaining ~$512K across the five chains.

We reached out to 0xaCc0…0E98 through Blockscan chat. The rescued funds were returned in full. The user's reply: "we were supposed to only approve to the Squid router address."

Source: @DefimonAlerts (Decurity) on X.

Three contra-cases

Squid was a small case with everything in its favor. The next three are larger, messier, and rescue worked partially or not at all.

Nomad — the attack was a one-line calldata copy, free for anyone to repeat, and there was no admin to stop them. Foom Cash — a whitehat secured the Ethereum side; on Base, a bounty hunter got there first and kept his cut under the protocol's bounty program. CrossCurve — no defender appeared, and the contracts drained to zero over a hundred minutes; only ~$19K came back later from other exploiters.

Nomad Bridge Aug 1, 2022
No emergency stop · Open to all

Once the first transaction landed on-chain, anyone watching could do the same.

Nomad was a cross-chain bridge — a contract holding deposits on Ethereum and releasing them to users on other chains in response to verified messages. In June 2022, a routine upgrade to its Replica contract broke the part responsible for that verification. The bug sat unnoticed for nearly two months. $190M sat in the bridge when someone finally found it.

The job of the Replica contract was simple: before paying out a withdrawal, confirm that the message requesting it was real. The June upgrade left this check with a hole — unverified messages were treated as if they had already been verified. Anyone could submit a withdrawal request that contained essentially nothing, and the contract would happily approve it and release the funds.

Nomad's auditors at Quantstamp had flagged a related concern in their June review (issue QSP-19). The team disagreed with the finding. Two months later, on August 1, someone proved them wrong. The first attacker's initial attempt failed and cost them $350K in gas. The second worked — four transactions in a single block, each claiming 100 WBTC.

From there it stopped being a hack and became open to all. The transaction was sitting on Etherscan, visible to anyone. Repeating it required no tooling, no skills, and no preparation — just changing the recipient address to your own and submitting it back to the network.

900+ transactions over 2.5 hours. Hundreds of addresses piled in. Dozens grabbed the exact same amount — $202,440 in USDC, the figure copied from the original transaction. The three biggest extractors took $47M, $40M, and $8M respectively. The bridge drained from $190M to near zero.

The Replica contract had no pause function. The team's first public acknowledgement came three hours after the exploit began. The attack was eventually halted by removing the Replica's authority over the bridge's funds — but by then the contract was empty. ~$36M came back voluntarily in the weeks that followed. The original attacker returned nothing.

Sources: rekt.news — "Nomad Rekt" · Immunefi — hack analysis.

Foom Cash Feb 26, 2026
Whitehat rescue · Bounty · Cross-chain

The same bug, hit simultaneously on two chains — with two very different outcomes.

On February 26, 2026, Foom Cash's FoomLottery contracts came under attack. A flaw in the zero-knowledge verifier setup let anyone withdraw without a valid proof. The same broken verifier was deployed on Ethereum and Base. ~$2.26M at risk across both chains.

$429K extracted at 07:23 UTC on February 26 — from the Base FoomLottery by @duha_real. duha — winner of Foom's own Bitcointalk hacking contest a year earlier — took the Base side under Foom's bounty program ("what you hack is yours"). Those funds stayed with duha as his recognised bounty.

On Ethereum, our whitehat bot Defimon identified the same flaw in the Ethereum verifier and executed a single rescue transaction at 07:39 UTC. ~$1.84M in FOOM moved out of the Ethereum FoomLottery and into custody we controlled — sixteen minutes after duha's first call. We returned the funds to Foom the same day, on-chain at 10:11 UTC, within hours of the rescue. Foom subsequently offered us a $100K security fee.

$1.84M returned to the Foom team. The remaining ~$429K stayed with duha as his bounty payout.

Sources: @Foomclub_, @DecurityHQ, @DefimonAlerts on X · rekt.news — "The Unfinished Proof".

CrossCurve Feb 1, 2026
No defenders · Authorization bypass

The bridge had two paths for processing messages. The attacker used the one with no security checks.

CrossCurve is a cross-chain bridge built on Axelar's messaging layer. Its architecture splits responsibility across two contract layers: a ReceiverAxelar contract that validates incoming cross-chain messages, and an Eywa CLP Portal that releases funds in response to those messages. Security depended entirely on the receiver doing its job.

Axelar's standard message flow requires that any cross-chain message be proof-backed and approved by the Axelar Gateway before the destination contract can act on it. The receiver contract calls validateContractCall(), which verifies the Gateway's approval against a specific payload — and marks it consumed, so it can't be replayed. That approval chain is what connects a real deposit on the source chain to a real release on the destination.

The ReceiverAxelar contract also had a second function: expressExecute(). It was designed as a fast path — for messages that had already been pre-approved — and it was publicly callable by anyone. The problem was that it skipped validateContractCall() entirely. Instead of checking the Gateway's approval, it verified only the sourceChain and sourceAddress fields embedded in the message itself — fields the attacker wrote. The check passed because the attacker made it pass.

From there the path was mechanical. The crafted message instructed the receiver to call unlock() on the Eywa CLP Portal, releasing bridged assets on the destination chain. The portal had no independent way to verify whether a corresponding deposit had ever been made on the source chain — that was the receiver's job, and the receiver had just been fooled. The attacker ran the same sequence on Ethereum and Arbitrum: ~$1.3M and ~$1.28M respectively. $2.76M drained — 15 transactions over roughly 100 minutes.

No pause mechanism existed, and no whitehat appeared. The contracts drained to zero — uncontested. ~$19K returned over the following days from other exploiters who had grabbed funds via the same bug (USDT, ETH, POL across four transactions on Feb 2-6) — less than 1% of the take.

Sources: @Phalcon_xyz on X · QuillAudits post-mortem · Olympix post-mortem.

Threshold table

What was left to save

Squid, Nomad, Foom, and CrossCurve showed four points on the spectrum. The full dataset has ten. The table below tracks each exploit at five points along its first hour: 1, 5, 15, 30, and 60 minutes after the first malicious transaction. Each cell is the share of funds at risk already gone by that mark — the further right a row stays low, the longer the window for a response.

A note on the denominator. Percentages are computed against funds at risk — the value actually reachable by the exploit vector, usually a single pool, contract, or approval pattern rather than the whole protocol. It's the dollar figure shown under each protocol name in the table.

Balancer V2 reached 54% in minute one and 93% in minute five. CrossCurve reached 57% in minute one. CrossCurve's recovery was tiny (~$19K returned post-hoc, less than 1%). The interesting question for Balancer isn't whether someone could pause — it's how a whitehat caught an attack moving that fast. Detail in the case below.

Six of ten still had 80%+ of at-risk funds on the table at five minutes: Euler (96%), Nomad (92%), Sonne (85%), Curve (84%), Foom (81%), and Squid (81%). Rhea started fast too — 95% at one minute — but the drain accelerated and crossed 20% by minute five. Seneca lost 65% in its first minute, putting it in the same fast-drain tier as Balancer and CrossCurve.

Funds still on the contract after the first transaction

The slider covers the first hour — the window where automated response is realistic. Pick a threshold and compare who's already empty and who's still full. Six of ten attacks lasted longer than 60 minutes; for those, the rightmost position still shows mid-attack. Duration is marked on each card.

In six out of ten cases, over 80% was still on the contract at five minutes. Funds were intercepted in three ways — each from outside the protocol, from infrastructure or authority the team didn't control.

  1. 01

    A bot faster than the attacker

    Front-running an exploit works on a narrow class of attacks: small enough that one or two next-block transactions cover the drain, and replay-friendly enough that a third party can fire the same primitive from a different address. That's how Bitfinding caught Balancer (~$1M, next block), c0ffeebabe.eth front-ran the Metronome pool on Curve Vyper ($5.4M) while Alchemix's own MEV bots pulled ~$11.5M out of the alETH pool in parallel, and our bot Defimon caught Foom ($1.84M of $2.26M at risk, 81%) and Squid ($512K of $623K at risk, 82%) — same pattern, same window.

    Sonne is the interesting case. Fuzzland's bot detected the attack and tried to copy the exploit on the remaining pools — but it failed. The attacker held a soVELO position that made the precision-loss vector impossible to replay without liquidating it first. Instead of attacking, Tony KΞ swapped ~$100 for VELO and deposited it into the soVELO pool — enough to remove the precision-loss condition entirely. The vulnerability became non-exploitable. ~$6.5M stayed in the pools.

  2. 02

    An issuer with admin keys over its own token

    The token contract itself can be the rescue surface — if the issuer keeps an admin path to it. StakeWise — ~$20.7M. Burned the attacker's osETH and osGNO balances via emergency multisig and re-minted them to a recovery address. Roughly three quarters of what the attacker took from those pools. Not Balancer's lever to pull; StakeWise's, and only because they shipped osETH/osGNO with that path in the first place. Tether — $4.34M of USDT frozen for Rhea, their standard freeze procedure, the same one they run dozens of times a year.

    Contrast Drift — a $285M Solana exploit two weeks before Rhea, not in this dataset — bridged ~$232M to Ethereum via Circle's own CCTP. USDC has the same freeze primitive USDT does. Circle didn't use it. The question wasn't "can the issuer freeze" — it was "will they". The protocol is now facing a class action and relaunching on USDT, with Tether stepping in to back the recovery.

  3. 03

    A hacker who could be talked down

    The only out-of-window mechanism in the dataset, and the one that recovered the largest absolute sums. Three levers, applied in sequence: a public bounty (typically 10%, "what you keep is yours, the rest comes back"), a credible legal-trace threat (CEX outreach, chain analytics, on-chain messaging to the attacker's address), and direct correspondence once the attacker engages. Euler ran all three over three weeks and got all $187M back after exposing the hacker identity. Rhea — ~$11.2M confirmed recovered of $18.4M through Tether freezes ($4.34M) and partial attacker returns; the remaining $7.2M covered from protocol reserves.

    The playbook doesn't always close — but it closes more often than not. Seneca — ~$5.4M returned of $6.5M (84%), keeping $1M. Curve — ~$22M returned from the Alchemix-pool attacker under the 10% offer; the JPEG'd attacker also returned; the CRV/ETH attacker never engaged. Nomad is the failure mode in plain view: no single attacker to negotiate with. Hundreds of copycats had piled in within 2.5 hours — a 10% bounty and a public refund address pulled ~$36M back out of $190.7M (~19%). The rest went to Tornado. Negotiation scales to one rational actor; it does not scale to a permissionless replay.

Three recovery paths, ten exploits — how did it all add up?

The result

How much came back

After the first transaction, how much could have been saved? The chart below splits each exploit's outcome by recovery path. Squid ($623K) and Euler ($187M) are three orders of magnitude apart, but both show high recovery — for completely different reasons. Euler took three weeks of negotiation. Squid took four minutes and a bot.

Green is whitehat rescue — autonomous, real-time, permissionless. Blue is post-hoc recovery — negotiation, issuer freezes, chain halts, bounty programs. Red is what stayed gone.

Same recovery rate, different mechanism. Seneca (84%), Squid (82%), Foom (81%) — nearly identical numbers, but Squid and Foom are green: a bot acted within minutes. Seneca is blue: the attacker returned funds days later, voluntarily.

Euler — 100%, but it took three weeks of negotiation and a legal trace. Rhea recovered 61% through a Tether freeze and partial attacker returns; the rest is covered from protocol reserves.

Curve (52%) is split roughly in half: whitehat front-runs by c0ffeebabe.eth and Alchemix bots on one side, attacker returns on the other. Sonne (33%) — Fuzzland neutralized the remaining pools, but what was already taken stayed taken. Balancer (28%) — StakeWise clawed back $20.8M from its own tokens; Bitfinding intercepted $1M in the next block after the attacker.

Post-hoc recovery required leverage specific to each case. Euler's $187M came back only after direct negotiation and a credible legal trace. Rhea confirmed ~$11.2M recovered of $18.4M: Tether froze $4.34M, the attacker returned $4.92M early, and ~$2M more came back under legal and CEX pressure. The remaining ~$7.2M is covered from protocol reserves. Seneca's attacker kept $1M and sent back $5.4M. Nomad's 10% bounty pulled $36M from hundreds of copycats. Each of these paths worked once — none of them were available to CrossCurve or the Curve pools that c0ffeebabe.eth didn't reach.

Whitehat rescue ran on a different basis entirely — no negotiation, no issuer, no legal trace. Our bot Defimon caught Squid ($512K) and Foom ($1.84M) within minutes. c0ffeebabe.eth front-ran the Curve Metronome pool for $5.4M while Alchemix bots pulled $11.5M in parallel. Sonne's Fuzzland neutralized the vulnerability before the attacker could drain the remaining $6.5M. In each case the bot moved before the protocol team knew what was happening.