Post-Mortem: How a Forged Message Minted $292M of rsETH Out of Thin Air
On April 18, 2026 a forged message released 116,500 rsETH (~$292M) from KelpDAO's bridge adapter. We trace the exploit, the attacker and the money on-chain.
Most DeFi exploits break a smart contract. This one didn’t touch the contract’s logic at all — the code did exactly what it was written to do. The attacker simply told it a lie the code had no way to check, and the contract handed over 116,500 rsETH worth about $292 million. It remains the largest crypto exploit of 2026 to date.
This is a forensic reconstruction of the KelpDAO rsETH exploit of April 18, 2026. Where the on-chain evidence lives on Ethereum mainnet, we walk it transaction by transaction in TraceFast, and every hash and figure below was decoded directly from transaction receipts before publishing. Where the story crosses into other chains or off-chain infrastructure, we say so and attribute it to the teams that traced it.
TL;DR
KelpDAO’s rsETH is a liquid restaking token that moves across chains using LayerZero. On Ethereum, a lock-and-mint adapter holds the “real” rsETH; on other chains, wrapped rsETH is minted against messages saying tokens were locked or burned elsewhere. The security of that whole arrangement rests on one question: can you trust the message?
On April 18, KelpDAO’s configuration answered that question with a single verifier — a 1-of-1 DVN (Decentralized Verifier Network) operated by LayerZero Labs. According to LayerZero’s own post-incident account, attackers compromised the RPC infrastructure that DVN relied on and used it to attest to a cross-chain message that never happened: a “burn” of 116,500 rsETH on Unichain that, on Unichain, never existed. Ethereum’s adapter believed the attestation and released 116,500 real rsETH to an attacker-controlled wallet.
No reentrancy. No integer overflow. No flash loan against the protocol itself. Just a forged permission slip and a bridge that had been told to trust exactly one signer. LayerZero has publicly attributed the operation to the DPRK’s Lazarus Group (the TraderTraitor cluster).
The exploit transaction
Open the release transaction on TraceFast. It is almost anticlimactic:
- Block: 24,908,285 — timestamp 2026-04-18 17:35:35 UTC (verified against the block header)
- From:
0x4966…575e(the attacker’s executor EOA) - To: LayerZero EndpointV2
0x1a44…728c - Method:
lzReceive - Gas used: 94,456. Fee: 0.000472 ETH.
Read that fee again. Draining $292 million cost the attacker under half a thousandth of an ether. There was no priority-fee auction, no builder bribe, no gas ladder — none of the machinery you see in an MEV sandwich, because this wasn’t a race for block position. It was a single privileged function call that the protocol had been tricked into authorizing. The attacker paid ordinary gas and walked out.
Inside that transaction, exactly one token movement matters. Decoded from the receipt logs:
rsETH (
0xa1290d…e5a7):0x85d4…8ef3→0x8b1b…0D3b— 116,500.000000 rsETH
That’s the whole heist in one line: the OFT adapter 0x85d456…98ef3 — the vault holding Ethereum’s locked rsETH — transfers 116,500 rsETH to the attacker’s wallet 0x8b1b…0D3b. Note a correction to several early write-ups here: 0x85d456…98ef3 is the adapter, not the rsETH token itself. The canonical rsETH ERC-20 is 0xa1290d…e5a7 — confirmed by calling name() and symbol() on it directly, both return rsETH. The distinction matters for anyone reproducing this: the token contract was never compromised; the adapter that trusted the bridge was.


Two transactions, not one
The release didn’t happen in isolation. The LayerZero receive path is two steps, and both are on-chain:
- Commit the verification —
0x68eb…b564, sent to ReceiveUln302 (0xc02a…24c2) two blocks earlier (24,908,283). This is the step that writes the forged attestation into Ethereum’s state. - Execute the message — the
lzReceivecall above, which reads that committed attestation and releases the tokens.
Both were sent by the same executor EOA 0x4966…575e. Its TraceFast profile is a tidy confession: nine transactions total, all clustered around the LayerZero receive contracts, including two failed lzReceive calls — the blocked follow-up attempts we’ll come back to. This is not a wallet that does anything else. It was created, it committed and executed forged messages, and it went quiet.
The attacker’s wallet
The recipient wallet 0x8b1b…0D3b tells the same disciplined story from the other side:
- Created: block 24,906,342 — under two hours before the exploit.
- Lifetime: seven transactions, all outbound, last active at 17:41 UTC — six minutes after the drain.
- Current ETH balance: ~0.098 ETH.
A wallet born two hours before the attack, used only to receive the loot and immediately fan it out, then abandoned inside ten minutes. Everything about the timing says pre-staged operation, not opportunistic discovery — consistent with the Lazarus attribution.

Follow the money
From here the trail leaves what we can decode from Ethereum mainnet receipts and enters territory mapped by dedicated on-chain investigators. We attribute it accordingly.
The 116,500 rsETH was not meant to be sold — dumping that much rsETH into the market would have crushed the price and stranded most of the value. Instead the plan was to use the deepest liquidity venue available: lending. Deposit rsETH into Aave V3, enable the correlated-asset “eMode,” and borrow WETH against it at ~99% loan-to-value — turning an illiquid, potentially-freezable restaking token into native ETH without ever touching a DEX order book.
We mapped all seven branches on-chain, and the full picture corrects both the reports and our own first pass. Within four minutes of the drain, the main wallet 0x8b1b…0D3b fanned the full 116,500 rsETH out to seven pre-staged branches (not the “~8” several write-ups cite), in amounts that sum to the drain exactly. But the branches did not all do the same thing — they split into two parallel exit strategies:
| Branch | rsETH | Route (verified on TraceFast + RPC) |
|---|---|---|
0x1F4C…adeF | 53,000 | Aave V3 → borrowed 52,440.58 WETH (98.94% LTV) |
0xeba7…129b | 30,000 | Compound III (WETH + wstETH markets; 3,905.85 wstETH borrowed) + bridged remainder |
0xcbb2…55cc | 10,000 | Euler (701 rsETH → 197.77 WETH, 28% LTV) + 9,299 rsETH bridged; 11.1 WBTC out |
0x1b74…644c | 8,000 | 8,000 rsETH bridged via LayerZero |
0xbb6a…c787 | 6,000 | 5,230 rsETH swapped via a DEX aggregator + 770 bridged |
0x8d11…c2d49 | 5,000 | 4,600 rsETH bridged + 400 to Aave (393.92 WETH, later repaid) |
0xe9e2…d181 | 4,500 | 4,500 rsETH bridged via LayerZero |
| Total | 116,500 |

Strategy one — borrow against it. A handful of branches used rsETH as collateral to borrow ETH-denominated assets, and they deliberately spread that borrowing across different money markets: Aave V3, Compound III (both its WETH and wstETH markets), and Euler. Concentrating 116,500 rsETH of borrow demand in one pool would have spiked utilization to 100% and the borrow rate with it; splitting across three protocols keeps each pool liquid. This is liquidity-aware laundering — and it’s exactly why our first scan, which looked only at Aave debt tokens, badly undercounted the operation and led us briefly to the wrong conclusion.
Strategy two — bridge it out. The larger surprise: roughly 40,000 rsETH — about a third of the entire haul — was never converted on Ethereum at all. Five of the seven branches routed rsETH into a single contract, 0xacddac…05f1 — a LayerZero MultiCall contract — which bridged it to other chains. This is what CoinDesk meant by wrapped ether left “stranded across 20 chains”: the attacker fired rsETH across LayerZero to a swarm of destination chains faster than any single chain’s defenders could react.
A third, smaller channel rounds out the toolkit: one branch (0xbb6a) pushed 5,230 rsETH through a DEX aggregator/swap contract rather than a lending market or the bridge — a direct on-DEX conversion. Between borrowing, bridging, and swapping, the operation used every liquidity primitive Ethereum offers, in parallel, in the same ten minutes.
And there’s the irony worth sitting with: the exploit abused a LayerZero verification flaw to mint the tokens, and then used LayerZero’s own messaging to launder them cross-chain. The same primitive on both ends of the crime.
Two branches we decoded to the last token:
0x1F4C…adeF — the Aave branch. Receives 53,000 rsETH (tx 0xe381…e70a), supplies all of it to Aave V3 (mints 53,000 aEthrsETH in four tranches: 1 + 5,000 + 20,000 + 27,999), and borrows 52,440.58 variableDebtEthWETH against it — a 98.94% LTV, right at the eMode ceiling, in under a minute of block time. The WETH was unwrapped to native ETH and swept out in a single 52,440.68 ETH transfer. This one wallet, 45% of the drain, is the single largest on-Ethereum conversion.
0xeba7…129b — the Compound branch. Routes its 30,000 rsETH into Compound III, across both the Compound WETH (cWETHv3) and Compound wstETH (cWstETHv3) markets, borrowing 3,905.85 wstETH out of the latter, cycling collateral between the two, and bridging the balance out via LayerZero. Same intent as the Aave branch, an entirely different venue — invisible to anyone watching Aave alone.
The one figure we leave attributed rather than reconstructed is rekt.news’s report of a collector holding ~75,700 ETH within 27 minutes (§) — a cross-venue aggregate we could not fully rebuild, and one that has to be read alongside the ~40,000 rsETH that left Ethereum entirely rather than becoming ETH here.
From ETH, the reported exit routes were THORChain (ETH→BTC), the Umbra stealth-payment protocol, Chainflip, and BitTorrent Chain — the standard cross-chain laundering menu, chosen specifically because BTC and native ETH sit outside any issuer’s reach.
Two responses clawed back part of it. The Arbitrum Security Council executed an emergency action freezing 30,766 ETH tied to the exploiter on Arbitrum One (per Chainalysis). And on Ethereum, the attacker’s own follow-up greed failed: two more forged packets targeting ~40,000 additional rsETH were submitted — those are the failed lzReceive calls visible on the executor’s profile — and reverted after KelpDAO paused the adapter, roughly 46 minutes after the first drain.
Sidebar: even Lazarus gets poisoned
While the exploiter was laundering $292 million, someone was trying to rob them.
At 18:01 UTC — about twenty minutes after the fan-out — the attacker’s wallet started collecting address-poisoning spam. Nine transfers landed over the next five minutes, and they came in two flavours. Some were zero-value transfers of the real rsETH token: a transferFrom(victim, lookalike, 0) needs no allowance, so anyone can push one, and it plants a row in the victim’s history that appears to come from the victim’s own wallet. The rest came from a counterfeit token at 0x9a50…dfd5, which can emit Transfer events for any amount it likes.
That fake token is a small piece of craft in its own right. Call symbol() on it and you get back twelve bytes that render as Тoken. The “Т” is not the Latin letter T — it is Cyrillic Те, U+0422, and the string is padded front and back with U+200A hair-spaces, an invisible character most naive filters and string comparisons sail straight past. It is a token engineered to look like nothing in particular and match nothing exactly.
The amounts were the giveaway of intent: 53,000, 30,000 and 10,000 — the exact sizes of the three largest branch payouts, aimed at the three largest branches. Each went to an address ground to match the real branch’s first four and last four hex characters. The real Aave branch 0x1f4c1c2e…0db3adef acquired a shadow at 0x1f4cf71e…9bdadef. Truncate either one the way every block explorer and wallet UI does, and they are the same address.

Look at those rows the way an ordinary wallet shows them, and the trap is plain. 0x1f4c…adef appears three times in this screenshot, and each time it is a different address — 0x1f4cf71e…, 0x1f4cd3e1…, 0x1f4c9ddc…, three separate vanity grinds. The branch that actually received the 53,000 rsETH is a fourth, 0x1f4c1c2e…0db3adef. Four distinct addresses, one identical short form — and the short form is all most interfaces ever show you.
The only reason the real one is distinguishable in the screenshot above it is that it isn’t rendered as hex at all: TraceFast has a label for it, so it reads Kelp DAO Exploiter: branch aave, while the freshly-ground doppelgangers — which no one has any reason to have heard of — stay anonymous. That is the inversion worth taking away. When every address collapses to eight characters, the defence isn’t reading them more carefully; it’s knowing something about the counterparty that the characters don’t tell you.
And it didn’t stop at the payouts — the poisoning shadowed the cash-out too. At 17:44 the Aave branch swept its borrowed ETH out in a single native transfer of 52,440.6761 ETH to a collector at 0x5d3919f1…0c257ccc. Beginning eleven minutes later, a swarm of counterfeit ERC-20 tokens replayed that exact figure: some named plainly ETH, others with homoglyph symbols — ĖTḨ (a Latin Ė, U+0116, and an H with cedilla, U+1E28) and EꓔH (with U+A4D4, a Lisu letter that renders as a passable T). Each was aimed at a look-alike of the collector, and the two homoglyph variants landed on 0x5d396d93… and 0x5d3977a1… — addresses that truncate to 0x5d39…7ccc, character for character the same short form as the real collector. Native ETH is never an ERC-20, so every one of those rows is a tell to anyone who looks; at a glance in a wallet’s history, it reads as the real thing.
The bet is simple: sooner or later the thief needs to move funds again, opens their own transaction history, copies what looks like a branch address, and wires the loot to a stranger. Poisoning is a numbers game played against muscle memory.
It never had a chance. The wallet had gone dormant at 17:41 — its last transaction ever — and the first poisoned transfer arrived twenty minutes later. The poisoners spent real money grinding vanity addresses to ambush a wallet that would never send another transaction. Their precision even improved as the five-minute window went on: the earliest lookalikes miss the target’s last four characters by a nibble, the later ones match exactly. Someone was still tightening their aim at a target that had already left.
There is something clarifying in that. A nation-state crew had just walked off with $292 million, and on the public ledger they were indistinguishable from any other fresh wallet holding a large balance — which is to say, prey. The same transparency that lets us reconstruct this heist transaction by transaction is the transparency that put a target on the thief’s back within twenty minutes. Everyone is visible to everyone. Nobody is exempt.
How the trick itself works, and how it lands on ordinary wallets, is the subject of a separate teardown: The Phantom Sender.
Timeline (April 18, 2026, UTC)
The entire value-extraction phase fit inside a single hour:
| Time | Block | Event | Evidence |
|---|---|---|---|
| ~15:45 | 24,906,342 | Attacker recipient wallet 0x8b1b…0D3b created | ✓ on-chain |
| 17:34 | 24,908,283 | Forged attestation committed to ReceiveUln302 (0x68eb…b564) | ✓ on-chain |
| 17:35:35 | 24,908,285 | lzReceive releases 116,500 rsETH from the adapter (0x1ae2…4222) | ✓ on-chain |
| 17:37 | 24,908,294–316 | Full 116,500 rsETH fanned out to 7 branches (sums exactly) | ✓ on-chain |
| 17:39–18:07 | 24,908,305–446 | Two parallel exits: borrow across Aave/Compound/Euler (52,440.58 WETH on Aave alone) and ~40,000 rsETH bridged out via LayerZero MultiCall (0xacddac) | ✓ on-chain |
| 17:41 | 24,908,316 | Attacker recipient wallet goes dormant (last tx) | ✓ on-chain |
| ~17:50 | — | Community alerts (~$100M initial estimate) | § reports |
| ~18:00 | — | Collector address holds ~75,700 ETH from 5 branches | § rekt.news |
| ~18:2x | — | Two follow-up forged packets (~40,000 rsETH) submitted and revert | ✓ on-chain (failed lzReceive) |
| ~18:21 | — | KelpDAO pauses the adapter (~46 min after the drain) | § KelpDAO |
| Apr 20 | — | Arbitrum Security Council freezes 30,766 ETH | § Chainalysis |
The gap that matters is the one between 17:35 and 18:21: forty-six minutes in which the attacker moved essentially unopposed. Everything that was recovered was recovered after the money had already been converted and was partly out the door.
The compliance angle — and why it didn’t help
Here’s a detail that turns a laundering footnote into a lesson. TraceFast’s compliance view tracks issuer-controlled blacklists — the on-chain AddedBlackList / Blacklisted events that Tether, Circle, and other stablecoin issuers emit when they freeze an address. At the time of writing it tracks 25,918 blacklisted addresses across 550 contracts — with Tether’s USDT (2,687) and Circle’s FiatTokenProxy/USDC among the most active issuers, alongside a long tail of smaller tokens running their own freeze lists.
Now line that up against the attacker’s exit strategy. If this operation had cashed out through USDC or USDT, Circle and Tether can — and routinely do — freeze the tokens at the contract level, and you would expect to see exactly those blacklist events fire against the collector addresses. But the attacker never touched a freezable stablecoin. They converted rsETH into ETH-denominated debt across lending markets (Aave, Compound III, Euler), then to native ETH and BTC via THORChain. Native assets have no issuer and no blacklist function. There is no AddedBlackList event that can touch them.
That is the whole game in one observation: issuer blacklists are a real control, and sophisticated attackers route around them on purpose. Watching the compliance feed tells you when Tether freezes a scammer’s USDT — and also, by its silence here, why nation-state operators don’t leave value in anything Tether can freeze. The absence of a blacklist event is itself a signal about the caliber of the adversary.

What actually failed
The vulnerability was never in Solidity. It was in trust configuration. Three architectural choices compounded:
- 1-of-1 verification. A single required DVN (
0x589d…236b, LayerZero Labs’) with zero optional verifiers means one compromised party can attest to anything. There is no quorum to disagree with a lie. LayerZero supports multi-DVN quorums; this deployment simply hadn’t set one. - Trusting mutable off-chain infrastructure. The DVN’s attestation was only as trustworthy as the RPC nodes feeding it. Compromise the nodes (per LayerZero, two internal nodes were swapped and external ones DDoS’d) and the on-chain attestation becomes a laundered lie with a valid signature.
- Lock-and-mint asymmetry with no source-side check. Ethereum’s adapter released real tokens on the strength of a “burn” it could not independently see. On Unichain, the outbound nonce never advanced past 307; the forged packet claimed nonce 308. The burn simply never happened — and nothing on the releasing side was required to notice.
Checklist for teams running a bridge
If you operate or integrate a cross-chain token, this incident is a short, expensive syllabus:
- Never ship 1-of-1. Require a quorum of independent DVNs/verifiers with no single operator able to finalize a message alone. The cost of an extra verifier is rounding error against $292M.
- Treat verifier RPC infrastructure as part of your trust boundary. If an attestation depends on nodes, those nodes are attack surface — segregate them, monitor for software swaps, and don’t let a DDoS on the honest path force a fallback to a compromised one.
- Add source-side reconciliation. A releasing adapter should be able to reject a message whose claimed nonce or burn has no counterpart on the source chain. Monitoring that flags “release with no matching source-side burn” would have caught this in the mempool.
- Rehearse the pause. KelpDAO’s pause worked — it blocked a second ~40,000 rsETH — but it landed 46 minutes in. Minutes are millions here.
- Watch your adapter’s balance as a first-class alert. A single transfer moving 116,500 rsETH out of the lock adapter is the kind of anomaly a balance-delta monitor surfaces instantly, no exploit knowledge required.
Reproduce this analysis yourself
The Ethereum-side evidence is fully public. Open the release transaction, read the single 116,500 rsETH transfer out of the adapter, then walk to the executor and the recipient wallet to see the two-step commit/execute pattern and the failed follow-ups for yourself. The compliance view is worth keeping open next to it — not because it caught this one, but because understanding why it couldn’t is half of understanding the attacker.
Next in the series: reading storage heatmaps to catch the anomalies that precede an exploit, before the money moves.