On April 13, an attacker exploited a bug in Hyperbridge’s Ethereum-side smart contracts. By submitting a carefully crafted fake cross-chain message, they bypassed the cryptographic verification and granted themselves admin/minting rights over the bridged DOT token contract on Ethereum. They then minted 1 billion bridged DOT tokens out of thin air and sold them for approximately $237,000 in ETH.

The real DOT on Polkadot was completely untouched. This was purely an attack on the Ethereum-side token representation.

https://etherscan.io/address/0xc513e4f5d7a93a1dd5b7c4d9f6cc2f52d2f1f8e7

https://etherscan.io/tx/0x240aeb9a8b2aabf64ed8e1e480d3e7be140cf530dc1e5606cb16671029401109

What Is Hyperbridge?

When you want to use a token from one blockchain on a completely different blockchain, you need a bridge a system that locks your tokens on the original chain and mints a wrapped representation on the destination chain.

Hyperbridge, built by Polytope Labs, is exactly this kind of infrastructure. It connects Polkadot (and its native token, DOT) to Ethereum and other EVM-compatible chains. When someone bridges DOT to Ethereum, Hyperbridge locks the real DOT on Polkadot and mints a “bridged DOT” token on Ethereum that represents it.

The key promise of Hyperbridge is that it’s trust-minimized — meaning you don’t need to trust a centralized operator. Instead, it uses cryptographic proofs to verify that cross-chain messages are legitimate before acting on them.

That proof verification is exactly where everything went wrong.

How Cross-Chain Messages Work in Hyperbridge

When Hyperbridge processes a cross-chain message arriving on Ethereum, it goes through a function called handlePostRequests. This function has one critical job: make sure the message actually came from Polkadot before doing anything with it.

It does this using a cryptographic structure called a Merkle Mountain Range (MMR) essentially a tamper-proof tree of data. Every legitimate message from Polkadot gets included in this tree, and its root hash gets stored on Ethereum. To prove a message is real, you submit a proof showing that your message is a leaf in that tree. The contract recalculates the root from your proof and checks if it matches the stored root. If it does, the message is genuine.

Root cause

The proof verification is handled by a function called CalculateRoot from a library called solidity-merkle-trees. This function has a quirk that turns into a catastrophic vulnerability.

When you call CalculateRoot with a single leaf, it checks if that leaf’s index is 0. If it is, it returns the leaf’s hash immediately (an early exit for this simple case). But if the leaf index is anything else say, 1 it skips that early exit and falls into the general calculation path.

Here’s what happens in that general path with a tree of only 1 leaf and an out-of-bounds index like 1: the function finds no valid leaves within the expected subtree, so it reaches into the provided proof array and pulls proof[0] directly into the result. After the loop finishes, proof[0] ends up as the returned “computed root.”

if you set leaf index to 1 and put the value you want returned inside proof[0], the function returns exactly that value regardless of what your actual message contains.

How the Attacker Used This

The attacker wanted to pass a fake ChangeAssetAdmin message — one that would hand them minting rights over the bridged DOT contract. To do this, they needed the proof verification to pass for a forged message.

They called handlePostRequests with:

Polkadot's most recent update indicates a significant but contained incident involving bridging assets rather than the core network. The core of the problem is a fault in Hyperbridge Ethereum gateway contract,
  • A fake message requesting admin rights
  • leaf_index = 1 (out of bounds for a 1-leaf tree)
  • proof[0] set to the actual stored Merkle root on Ethereum

When CalculateRoot ran, it ignored the fake message’s hash entirely, pulled proof[0] straight into the result, and returned it as the “computed root.” The contract then compared this computed root against the stored root and they matched perfectly, because the attacker had simply put the stored root inside the proof.

Verification passed. The fake message was accepted as legitimate. The attacker got minting rights, printed 1 billion bridged DOT, and dumped them.

Why Nobody Caught It

Misleading trust in external libraries. The calling code passed untrusted user input directly into a security-critical function without any sanitization. Developers generally assume libraries validate their own inputs — this one didn’t, and that assumption wasn’t documented anywhere.

The Takeaway

Hyperbridge’s core promise is cryptographic trust the idea that you don’t need to trust anyone because the math guarantees correctness. When the math has a hole in it, that guarantee evaporates entirely.

One missing bounds check in a Merkle proof library let an attacker turn “prove your message is real” into “just tell us what root you want us to compute.” $237,000 and a serious reputation hit later, the lesson is straightforward: cryptographic infrastructure needs adversarial testing, not just unit tests, and external libraries must never receive unsanitized user input in security-critical paths.

LEAVE A REPLY

Please enter your comment!
Please enter your name here