Ethereum
Signature and replay

Hyperbridge's $2.5M Loss and How Olympix Would Have Prevented It

Loss
Loss
Exploit date
April 13, 2026

Date: April 13, 2026

Chain: Ethereum, with incentive-pool losses on Base, BNB Chain and Arbitrum

Loss: about $2.5M in realized losses, per Hyperbridge

Class: Merkle Mountain Range proof check that never bounded the leaf index

On April 1, 2026, Hyperbridge announced on X that the Lazarus Group had drained it of $37M, and linked to a blog post titled "Why Hyperbridge Can't Be Hacked." It was an April Fools' joke, and both posts were later deleted. Twelve days later, at 03:55:23 UTC on April 13, a single Ethereum transaction minted 1,000,000,000 bridged DOT out of nothing and pushed every one of them into a Uniswap V4 pool, against a legitimate circulating supply that Range puts at about 356,000.

The mint was only the visible half. About fifty minutes earlier, another address had pulled 245.93 WETH out of Hyperbridge's Token Gateway, and Hyperbridge later said the same flaw allowed attackers to both "mint assets and drain escrowed assets on Token Gateway." Its first public figure was $237,000; three days later it revised the realized loss to about $2.5M across Ethereum, Base, BNB Chain and Arbitrum. Every one of those losses traces back to a few lines of a Merkle proof library that accepted a leaf position outside the tree it was supposed to belong to.

A Bridge That Trusts Proofs Instead of Signers

Hyperbridge, built by Polytope Labs, connects Polkadot to EVM chains using the Interoperable State Machine Protocol (ISMP). Its design doesn't rely on a committee of signers: a message from the Hyperbridge chain is accepted on Ethereum only if it comes with a cryptographic proof that the message is part of a state commitment the Ethereum side already knows. After the incident, Hyperbridge said it still holds that "cross-chain interoperability is only secure through cryptographic proofs," pointing to more than $2.8 billion lost industry-wide in two years, mostly through compromised signers and multisigs.

On Ethereum, three contracts do the work. The EvmHost stores state commitments from Hyperbridge, including a value called the overlay root for each finalized height. HandlerV1 receives incoming messages from relayers, checks them against that overlay root, and hands the valid ones to the host for delivery. Token Gateway is the application that receives those messages: it releases escrowed assets for incoming transfers and manages bridged tokens like DOT on Ethereum, which are ERC6160 tokens whose admin and minting rights Token Gateway controls.

That last role is why the Token Gateway held so much power. Besides ordinary transfers, it accepts governance-style messages from the Hyperbridge chain, including one called ChangeAssetAdmin. In the verified Token Gateway source on Etherscan, its handler checks only that the request's source is the Hyperbridge chain and that the asset exists, then calls changeAdmin on the token with whatever new admin the message names. That's a reasonable design if the proof layer underneath is airtight, because a message that claims to come from Hyperbridge only reaches the gateway after HandlerV1 has verified it.

The Proof Check That Skipped Its Own Leaf

A Merkle Mountain Range (MMR) is an append-only structure that stores a growing list of items, in this case request commitments, as a series of perfect binary trees called peaks. To prove an item is in the range, you supply the item's hash, its position among the leaves, the total number of leaves, and the sibling hashes needed to rebuild the root. The verifier hashes everything back up and compares the result to the root it already trusts. A proof only means something if the verifier actually uses the thing being proven, and that's the lesson this exploit teaches.

HandlerV1 builds each leaf from the incoming request. From the verified HandlerV1 source on Etherscan, inside handlePostRequests:

bytes32 commitment = leaf.request.hash();
if (host.requestReceipts(commitment) != address(0)) revert DuplicateMessage();

leaves[i] = MmrLeaf(leaf.kIndex, leaf.index, commitment);
...
bytes32 root = host.stateMachineCommitment(request.proof.height).overlayRoot;
if (root == bytes32(0)) revert StateCommitmentNotFound();
bool valid = MerkleMountainRange.VerifyProof(root, request.proof.multiproof, leaves, request.proof.leafCount);
if (!valid) revert InvalidProof();

The commitment is computed honestly from the request, but the leaf's position (leaf.index) and the tree size (request.proof.leafCount) both come straight from the caller's calldata. Verichains' analysis points out that HandlerV1 passes both to the verifier without checking them. VerifyProof then calls CalculateRoot in Polytope Labs' MerkleMountainRange library, which ships inside the same verified HandlerV1 source:

// special handle the only 1 leaf MMR
if (leafCount == 1 && leaves.length == 1 && leaves[0].leaf_index == 0) {
    return leaves[0].hash;
}
...
    MmrLeaf[] memory subtreeLeaves = new MmrLeaf[](0);
    if (leaves.length > 0) {
        (subtreeLeaves, leaves) = leavesForSubtree(
            leaves,
            current_subtree
        );
    }

    if (subtreeLeaves.length == 0) {
        if (proofIter.data.length == proofIter.offset) {
            break;
        } else {
            push(peakRoots, next(proofIter));
        }
    }

The first block is a shortcut for a range with a single leaf at position zero, where the leaf's own hash is the root. The loop below it walks the peaks of the range and asks leavesForSubtree which of the supplied leaves fall inside each one. When a peak contains none of them, the code assumes the proof supplies that peak's hash and takes the next proof element as given. Nothing in the function requires a leaf's position to be smaller than the number of leaves.

Put those together and a leaf can be given a position that lies outside every peak. The leaf then never lands in any subtree, so its hash, the request commitment HandlerV1 so carefully computed, is never used. The root that comes out the other end is assembled entirely from proof elements the caller chose, so a caller could make that root match the overlay root the host already stores. Phalcon's final update, as quoted by Rekt, summarized it in one line: "The verifier does not enforce leaf_index < leafCount." A bounds check of that shape is exactly the fix Verichains proposes.

Two Waves on April 13

The first wave came from address 0xc056...F143. At 03:02:11 UTC, in block 24868029, it deployed a contract in a transaction that moved 245.930356583188974044 WETH out of the Token Gateway contract into a helper at 0xCcd3...5a5d, which unwrapped it to ETH in the same transaction. Decrypt valued the 245 ETH at about $561,000. According to Rekt, citing SpecterAnalyst, the ETH was split across 15 wallets of about 16.39 ETH each before heading to Tornado Cash.

The second wave belonged to address 0xC513...F8E7, which Range says was funded through Railgun and Synapse Bridge and had been active for about 33 days. Verichains records a small test transaction from it at 03:39 UTC. At 03:55:23 UTC, in block 24868295, the main transaction deployed a minimal proxy at 0x518A...8f26 that called HandlerV1.handlePostRequests with a forged ChangeAssetAdmin message. The proof passed for the reason above, the host delivered the message to Token Gateway as if it came from Hyperbridge, and Token Gateway handed admin and minting rights over bridged DOT to the attacker's pre-deployed contract at 0x31a1...a9AB.

The rest of the transaction is visible in its token transfers on Etherscan. Bridged DOT at 0x8d01...90b8 minted 1,000,000,000 DOT from the zero address to 0x31a1...a9AB, which passed them to a routing contract at 0x3650...b5b8, which sold them into the Uniswap V4 PoolManager. Range and Verichains put the proceeds at about 108.2 ETH, roughly $237,000, routed through Odos Router V3, for about $0.74 in gas. The pool's price for bridged DOT fell from about $1.19 to near zero.

The same pipeline kept going. Verichains lists a mint of about 1 billion ARGN at 04:20 UTC and further bridged DOT mints at 04:26, 04:33, 04:51 and 05:07 UTC, each worth less than the last as the pools emptied. Hypernative reports that Polytope Labs told users to treat every ERC6160Ext20 token issued through the same Token Gateway, including ARGN, ARGNOT, MANTA and CERE, as compromised. Range adds that a smaller drain of about $12,000 in MANTA and CERE used the same flaw earlier that day.

Downstream Barriers That Weren't There

The forged proof was the root cause, but nothing downstream slowed it. HandlerV1 skips its challenge window whenever the host's challengePeriod is zero (the check reads challengePeriod != 0 && challengePeriod > delay), and Hypernative reports that the Ethereum host's challenge period was set to zero. Hypernative also notes there was no delay or confirmation on the admin change and no supply cap on the bridged token, so a single forged message could change ownership and mint a supply roughly 2,805 times the real one in the same call.

Together, those gaps meant that once the proof layer accepted one bad message, nothing on-chain stood between it and the bridged token's supply.

From $237K to $2.5M

Hyperbridge paused bridging after the attack, and Polkadot's team confirmed the incident was isolated to Hyperbridge's Ethereum-side infrastructure. Native DOT still dipped about 6% on centralized exchanges, according to Range, and Upbit and Bithumb temporarily suspended DOT deposits and withdrawals.

Hyperbridge's first public estimate was about $237,000, the observable proceeds of the DOT sell-off. On April 16, The Block reported the revised figure of about $2.5M, which Hyperbridge said covers the 245 ETH drain, attacker activity reconciled across four chains, and losses in incentive pools on Ethereum, Base, BNB Chain and Arbitrum that the first count missed. Those pools included liquidity positions recruited through Polkadot's DeFi Singularity campaign, and on the Polkadot forum an affected liquidity provider opened a pre-proposal for a DOT recovery loan that estimated LP losses at $1.5M to $1.8M before rewards.

Hyperbridge said a significant portion of the funds had been traced to Binance and that it was working with the exchange's compliance team and law enforcement, while warning that recovery could take months or up to a year. If recovery falls short, it committed to a structured BRIDGE token allocation to cover the residual loss, distributed one year from the exploit. Rekt, citing Arkham, separately reports that the main minting wallet sent about $269,000 to Tornado Cash.

On June 15, 2026, Hyperbridge announced in a sponsored press release that bridging had resumed after "a full architectural overhaul of the Token Gateway" and an audit with SRLabs, and that it had paid more than $150,000 to over 20 security researchers through HackenProof.

Why the Library Stayed Out of Focus

The vulnerable function lives in a shared library, Polytope Labs' solidity-merkle-trees, that HandlerV1 imports as a dependency. According to Rekt, SR Labs' June 2024 audit of Hyperbridge's Solidity modules found and saw fixed a high and a medium issue, and it listed "Exploit a bug in validation scheme to accept an invalid transaction" among the high-value threats. The same report also noted that its "investigation conducted on EvmHost.sol and HandlerV1.sol was heavily constrained in scope" and recommended specialist review of the custom libraries.

An audit covers the scope it's given in the time it has, and here the bug sat one step below the reviewed contracts, in a library whose correctness every proof on Ethereum depended on. Hyperbridge said afterward that "verification logic needs more frequent audits and adversarial testing at every layer of the stack," and the code shows why: the handler did its own checks correctly, and the missing check sat in the library underneath them.

How Olympix Turns a Proof Verifier Against Itself

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it works on the code a team actually compiles, including the libraries that code imports. For HandlerV1, the state that matters is which messages the host will deliver, and handlePostRequests is the entry point anyone can call. The engine maps every path from that entry point to dispatchIncoming and uses signals to decide which ones deserve an attack. Olympix's static analysis surfaces the signal here: values that come straight from calldata, a leaf position and a tree size, decide which branch of the proof computation runs, and on one branch the computed root comes entirely from caller-supplied proof data without consuming the leaf at all.

From the code and the protocol's design, the engine infers the invariant the bridge depends on but never writes down: a message may be delivered only if its own commitment is hashed into the overlay root the host trusts. That narrows the search fast. Of all the paths through handlePostRequests, the feasible ones that reach dispatchIncoming must pass VerifyProof, and the ones that touch the invariant are those where the request commitment and the computed root come apart.

BugPoCer runs Counterexample-Guided Invariant Refutation against that rule, working outward from the bridge as a whole and executing paths through the verifier until one breaks it. The counterexample for this case is short. A caller submits a post request whose commitment the host has never seen, sets a leaf position the tree doesn't contain, and supplies a proof whose elements rebuild the stored overlay root on their own. VerifyProof returns true, the host dispatches the message, and Token Gateway changes a bridged asset's admin to an address the caller controls. BugPoCer returns that sequence of state changes with the minimal conditions that trigger it and a generated Forge test that replays it, which is the April 13 attack produced in development instead of on mainnet.

Because Olympix runs automatically in development, at every merge and before release, the finding would have surfaced the moment the handler was built against the library, and again at every later merge that touched either one. It wouldn't depend on whether a library sat inside or outside a review's scope, since the engine follows the call into whatever code the contract actually executes.

A Proof Is Only as Strong as Its Inputs

Hyperbridge made a sound bet on cryptographic proofs, and the proof system failed on the one input it didn't bound. For any team that verifies Merkle, MMR or similar proofs on-chain, every index, size and offset that comes from calldata is part of the attack surface, and the invariant worth testing is the plain one: the thing being proven has to be part of what gets checked. To see how Olympix maps the paths through your own verifiers and returns a runnable counterexample for every one that breaks, book a technical walkthrough.

On-Chain References

Protocol: Hyperbridge Token Gateway (Polytope Labs)

Chain: Ethereum

Date: April 13, 2026, 03:02:11 UTC (WETH drain) and 03:55:23 UTC (bridged DOT mint)

Loss: about $2.5M across Ethereum, Base, BNB Chain and Arbitrum (Hyperbridge's revised figure)

HandlerV1 (vulnerable verifier): 0x6C84...6D64

Token Gateway: 0xFd41...B6dE

Bridged DOT token: 0x8d01...90b8

WETH drain attacker: 0xc056...F143

WETH drain helper contract: 0xCcd3...5a5d

WETH drain tx (245.93 WETH): 0xeff1...2d59

DOT mint attacker: 0xC513...F8E7

Pre-deployed mint and swap contract: 0x31a1...a9AB

Minimal proxy created in the exploit: 0x518A...8f26

Main exploit tx (1,000,000,000 DOT minted): 0x240a...1109

Block: 24868295

ARGN mint tx: 0xb28a...ac09

Further DOT mint tx (04:33 UTC): 0x743f...7125

Sources

Verichains: How a Missing Bounds Check Led to $237K Exploit on Hyperbridge

Rekt: Hyperbridge

Hypernative: How Three Compounding Failures Let an Attacker Mint $1.2B in Bridged Tokens

Range: 1 Billion Tokens Minted Inside the Hyperbridge Gateway Exploit

The Block: Hyperbridge Revises Exploit Losses to $2.5 Million

Decrypt: Polkadot-Ethereum Bridge Hack Losses Were 10x Worse Than Reported

See what Olympix finds on your own code

Send us a repo that's already been audited, and we'll run Olympix at the same commit and show you what comes back.