Inside the Kelp DAO rsETH Bridge Exploit, the Wallet Cluster, and the Real Failure Behind the Headlines

None

After i got rejected from one of blokchain investigator from one of the most credible in the market, i just wanted to make this space more aware of it and i wanted to make sure i wanted to create post every evidence that i found in the space and so suddenly, Arkham create a post that KELPDAO EXPLOIT, this was real issue after the incident of drift protocol.

On April 18, 2026, Kelp DAO lost roughly 116,500 rsETH, worth about $292 million, in one of the largest DeFi incidents of the year. Within minutes, the funds released from the bridge were split across several operational wallets, posted as collateral into lending protocols, and partially consolidated into other wallets in the form of ETH.

At first glance, it sounds like a familiar crypto story: a bridge gets hacked, funds disappear, and the ecosystem panics. But a closer look shows that this was not a story about a token bug, a classic reentrancy issue, an arithmetic failure, or a core contract that simply broke.

This was a story about a single forged cross-chain message being accepted as valid.

And once that message was accepted as truth, the system did exactly what it had been programmed to do: release real assets from escrow.

That is why Kelp DAO is worth reading not just as another bridge hack, but as a trust-boundary failure. What failed was not the core rsETH logic. What failed was the assumption about who was allowed to tell the bridge that a burn on another chain had really happened.

The Transaction That Changed Everything

None

The center of gravity in this incident is a single Ethereum transaction:

0x1ae232da212c45f35c1525f851e4c41d529bf18af862d9ce9fd40bf709db4222

That transaction called LayerZero EndpointV2 at:

0x1a44076050125825900e736c501f859c50fE728c

The payload claimed to originate from Kelp DAO's peer on Unichain, with Endpoint ID 30320 and nonce 308. On-chain queries show that the Kelp adapter really did store the peer for EID 30320 as:

0xc3eAcf0612346366Db554C991D7858716db09f58

So from the perspective of the receive path, the packet appeared to come through a normal channel. Not from a random sender. Not from an unknown address. That is exactly what made the exploit so dangerous: it did not try to look strange. It tried to look valid.

The target of the message was Kelp DAO's rsETH adapter on Ethereum:

0x85d456B2DfF1fd8245387C0BfB64Dfb700e98Ef3

Once the message was accepted, the adapter released 116,500 rsETH from escrow to:

0x8B1b6c9A6DB1304000412dd21Ae6A70a82d60D3b

This wallet was the initial exploit receiver, not the final destination of the funds. That distinction matters. In many large incidents, the first wallet to receive the assets is only a distribution node. That pattern is clearly visible here.

This Was Not an rsETH Token Bug

This is where public framing often goes wrong.

The core rsETH contract on Ethereum does not appear to have minted tokens out of thin air. What happened instead was that the bridge adapter behaved according to its design: if a cross-chain message is treated as valid, escrow must release tokens to the recipient specified in the payload.

The execution path is straightforward:

  1. EndpointV2.lzReceive executes a message that has already passed verification and commit.
  2. OAppReceiver.lzReceive checks that the caller is the official endpoint and that the sender matches the configured peer for that srcEid.
  3. OFTCore._lzReceive decodes the payload into a recipient and an amount.
  4. OFTAdapter._credit calls safeTransfer on the underlying token, moving assets from escrow to the recipient wallet.

This is the core problem: once message verification collapses, there is no second economic check that says,

"hold on, did the burn on the source chain really happen?"

The system assumes that question has already been answered by the verification layer. Because the answer that came in was "yes," escrow released real funds.

That is why this exploit looks like a counterfeit unlock. Not because the attacker minted rsETH from nothing in the core token contract, but because the attacker convinced the bridge that there was a legitimate reason to release rsETH from Ethereum escrow.

The Attack Path, Step by Step

Credit to Banteg's technical post mortem of exploit

To understand why a single forged packet was sufficient to drain the entire escrow, you need to walk the execution path at the code level.

Step 1: Attacker submits the forged packet to EndpointV2

// LayerZero EndpointV2.sol (simplified)
// https://github.com/LayerZero-Labs/LayerZero-v2

function lzReceive(
    Origin calldata _origin,               // { srcEid, sender, nonce }
    address _receiver,
    bytes32 _guid,
    bytes calldata _message,
    bytes calldata _extraData
) external payable {
    // Verification is assumed complete at the commit stage.
    // If the DVN pipeline has already marked this packet as valid,
    // this function executes without further economic checks.
    _requireVerified(_origin, _receiver, _guid);
    ILayerZeroReceiver(_receiver).lzReceive{ value: msg.value }(
        _origin, _guid, _message, msg.sender, _extraData
    );
}

The critical detail here is what _requireVerified does and does not do. It checks whether the packet has been committed by a registered DVN. It does not independently verify whether a burn on the source chain actually occurred. That question is fully delegated to the DVN layer and if the DVN layer is compromised, no further on-chain logic stops the message.

Step 2: OAppReceiver checks the caller and the configured peer

// OAppReceiver.sol (LayerZero OApp standard)

function lzReceive(
    Origin calldata _origin,
    bytes32 _guid,
    bytes calldata _message,
    address _executor,
    bytes calldata _extraData
) public payable virtual override {
    // Check 1: caller must be the official endpoint
    if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);

    // Check 2: sender must match the peer configured for this srcEid
    // ⚠️ This is where the exploit passes — the peer for EID 30320
    // was legitimately registered as 0xc3eAcf...
    // The attacker did not need to change the peer mapping.
    // They only needed to compromise the DVN that authenticated the message.
    if (peers[_origin.srcEid] != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);

    _lzReceive(_origin, _guid, _message, _executor, _extraData);
}

This is a subtle but important point. The forged packet did not fail the peer check because peers[30320] pointed to 0xc3eAcf..., which was already the legitimately registered peer address for the Unichain channel. The attacker did not need to tamper with the peer mapping at all. They only needed to convince the DVN to attest to a message that was never actually sent from that peer.

Step 3: OFTCore decodes the payload and calls _credit

// OFTCore.sol

function _lzReceive(
    Origin calldata /*_origin*/,
    bytes32 _guid,
    bytes calldata _message,
    address /*_executor*/,
    bytes calldata /*_extraData*/
) internal virtual override {
    // Decode the payload: recipient address and token amount
    (bytes32 toAddress, uint256 amountSD) = OFTMsgCodec.decode(_message);

    address toAddressDecoded = address(uint160(uint256(toAddress)));
    uint256 amountReceived = _credit(toAddressDecoded, _toLD(amountSD), false);

    emit OFTReceived(_guid, origin.srcEid, toAddressDecoded, amountReceived);
}

The payload the attacker crafted contained two values:

  • toAddress0x8B1b6c9A6DB1304000412dd21Ae6A70a82d60D3b (the initial exploit receiver)
  • amountSD → equivalent to 116,500 rsETH

Both values were fully attacker-controlled. Because the message passed verification, the adapter decoded them as legitimate instructions.

Step 4 : OFTAdapter releases rsETH from escrow

// OFTAdapter.sol

function _credit(
    address _to,
    uint256 _amountLD,
    bool /*_isOFT*/
) internal virtual override returns (uint256) {
    // There is no secondary economic check here.
    // The system fully trusts that the corresponding burn
    // on the source chain already happened,
    // because the DVN said so.
    innerToken.safeTransfer(_to, _amountLD);
    return _amountLD;
}

This is the final unlock. No oracle confirmation. No timelock. No cross-check against source chain state. One message accepted as valid → escrow opens. The adapter's job is only to execute what the messaging layer has already decided is true.

This is not a code bug in the conventional sense. Every function here is doing exactly what it was designed to do. The failure was upstream, in the assumption that the verification layer could not be compromised.

A Configuration That Trusted Too Much

The most important on-chain evidence in this case is not just the exploit transaction. It is also the receive-path configuration behind it.

When the ULN / DVN configuration for the Kelp adapter on source EID 30320 was queried on-chain, it showed a very weak security shape:

  • requiredDVNCount = 1
  • optionalDVNCount = 0
  • threshold = 0

In practical terms, that meant a single required DVN was enough for the message to be accepted. There was no second verifier. No optional quorum. No meaningful fault tolerance.

That is not just a technical detail. It means one source of truth was effectively enough to open the door to the entire escrow.

We often talk about decentralization in terms of governance, validator sets, or token distribution. But in bridge systems, the form of decentralization that matters most is often buried in a much more boring place: who is allowed to authenticate a message.

In Kelp DAO's case, that boring detail turned out to be the most expensive weak point in the system.

Where the Money Went First

After 0x8B1b6c… received 116,500 rsETH, the funds were immediately split into several major branches. The first-hop splits I was able to confirm on-chain were:

  • 53,000 rsETH to 0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF
  • 30,000 rsETH to 0xeBA786C9517a4823A5cFD9c72e4E80BF8168129B
  • 10,000 rsETH to 0xCBb24A6B4DAfaAA1a759A2F413eA0eB6AE1455CC
  • 8,000 rsETH to 0x1b748B680373A1dD70a2319261328CAb2A6f644C
  • 6,000 rsETH to 0xBb6A6006Eb71205e977eCeb19FCaD1C8d631C787
  • 5,000 rsETH to 0x8d11AeAC74267DD5C56D371bf4AE1AFA174C2d49
  • 4,500 rsETH to 0xe9e2f48bb0018276391aec240abb46e8c3cad181

This kind of split usually serves two purposes.

First, it spreads risk. If one wallet gets flagged or frozen, the other branches can keep moving. Second, it allows the attacker to operate in parallel across several protocols and liquidity routes almost immediately.

That is the moment when a bridge exploit becomes a cross-protocol systemic incident.

The Most Important Wallet Was Not the First Receiver

If you only look at the first transaction, your attention naturally stays on 0x8B1b6c…, because that wallet received the full 116,500 rsETH directly from escrow.

But if you read the flow of funds as an operation rather than as a single event, a more important wallet appears:

0x5d3919F12bCc35c26Eee5F8226A9bee90c257Ccc

Why?

Because on April 18, 2026 at 17:44:47 UTC, the wallet:

0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF

transferred 52,440 ETH to 0x5d3919….

That transfer was later highlighted publicly by Whale Alert. From an investigative standpoint, it is one of the strongest public signals in the case: 0x1F4C… appears to have functioned as a working wallet, while 0x5d3919… looks much more like the primary ETH consolidation wallet.

In other words, if 0x8B1b… was the exploit receiver, then 0x5d3919… looks more like the treasury wallet of the operation.

That distinction matters because it changes where analysts should pivot next.

How the Stolen rsETH Was Used

One reason this incident rattled so many protocols is that the attacker did not wait long to put the released rsETH to work.

The 0x1F4C… branch appears to have been used against the Aave rsETH market (0x2d62109243b87c4ba3ee7ba1d91b0dd0a074d7b1). The deposits I was able to confirm include:

  • 1 rsETH
  • 5,000 rsETH
  • 20,000 rsETH
  • 27,999 rsETH

The 0xeBA… branch sent:

  • 1,000 rsETH
  • 25,000 rsETH

to Compound V3 cWETHv3 0xA17581A9E3356d9A858b789D68B4d866e593aE94.

Meanwhile, the 0xCBb… branch made smaller but still meaningful deposits into Euler Prime rsETH

0x1924D7fab80D0623f0836Cbf5258A7FA734EE9D9:

  • 1 rsETH
  • 200 rsETH
  • 500 rsETH

The pattern of "small deposit first, then scale up" is typical of an operator validating execution routes before increasing size. It is not panic behavior. It is disciplined behavior.

Why Kelp DAO Matters Beyond Kelp DAO

The lesson here is much larger than one protocol.

Over the last two years, DeFi has trained itself to think of smart contract bugs as the main source of catastrophic risk. That is still true in many cases. But incidents like Kelp DAO show that configuration risk and cross-chain verification risk can be just as dangerous, and often harder to detect because they frequently live outside the normal scope of a Solidity audit.

A standard bridge adapter can be "correct" in code and still be dangerous if the trust model underneath it is too thin.

Kelp DAO also shows something else: how quickly a failure at the messaging layer can propagate into lending markets, collateral assumptions, peg confidence, and the market's broader risk perception of liquid restaking tokens.

In other words, when the bridge fails, it does not just drain one escrow. It damages confidence in the composability built on top of that asset.

Was This Lazarus?

This is the section where discipline matters most.

I see two separate layers of claims here.

The first is the on-chain exploit path. That part is strong. We can verify the exploit transaction, the first receiving wallet, the split into operational wallets, the deposits into external protocols, and the large ETH transfer into a consolidation wallet.

The second is the attribution to the Lazarus Group. Here I am much more cautious.

Unchained reported that LayerZero, in a postmortem referenced on April 20, 2026, linked the exploit to Lazarus / TraderTraitor with "preliminary confidence." The same reporting also described Tornado Cash pre-funding, compromised verifier infrastructure, and a DDoS-assisted failover as part of the broader attack chain.

All of that makes the attribution plausible. Possibly even quite strong.

But methodologically, I would still stop short of calling it independently proven based only on the public record available right now. Until a full postmortem, more infrastructure evidence, or additional confirmation from law enforcement or independent forensics becomes public, the most honest label remains: preliminary attribution.

The Addresses Worth Watching

If you want to continue the investigation in Arkham, these are the addresses most worth using as anchors:

  • 0x4966260619701a80637cdbdac6a6ce0131f8575e — exploit transaction caller
  • 0x85d456B2DfF1fd8245387C0BfB64Dfb700e98Ef3 — Kelp rsETH OFT adapter / escrow
  • 0x8B1b6c9A6DB1304000412dd21Ae6A70a82d60D3b — initial exploit receiver
  • 0x1F4C1c2e610f089D6914c4448E6F21Cb0db3adeF — largest operational branch
  • 0xeBA786C9517a4823A5cFD9c72e4E80BF8168129B — Compound branch
  • 0xCBb24A6B4DAfaAA1a759A2F413eA0eB6AE1455CC — Euler branch
  • 0x5d3919F12bCc35c26Eee5F8226A9bee90c257Ccc — likely primary ETH consolidation wallet

If I had to choose one wallet to watch after 0x8B1b…, I would start with 0x5d3919….

None
None

Closing Thoughts

Kelp DAO matters not only because the number is large, but because it reveals an uncomfortable truth: in cross-chain architecture, messages are money.

If a system treats one authenticated message as final truth, then anyone who can counterfeit that truth effectively holds the key to escrow.

That is what makes this incident feel so modern. There was no spectacular opcode-level exploit. No dramatic bug in the core token logic that could serve as an easy scapegoat. Instead, the failure was quieter: trust stretched too thin, living in a part of the stack few people ever read closely, and then becoming catastrophically expensive the moment it failed.

And like many of the biggest incidents in DeFi, the real damage came not from what was visibly broken in the main codebase, but from what everyone had assumed was safe at the edge of the system.

Methodology Note

This article is based on a combination of reproducible on-chain evidence and public secondary sources. The parts I consider strongly confirmed are the exploit transaction, peer mapping, the 1-of-1 receive-path configuration, the initial wallet split, the protocol deposits, and the large ETH transfer to 0x5d3919…. The part I still consider preliminary is the final attribution to the Lazarus Group.