Are cross-chain bridges safe? How bridge hacks happen · Jumpstart Blockchain
Are cross-chain bridges safe? How bridge hacks happen
A bridge is only as safe as whatever verifies cross-chain messages. Most major hacks came from stolen validator keys, verification bugs, or bad upgrades, not the chains themselves.
A bridge is only as safe as the thing that decides "this deposit really happened on the other chain". Chain A can't see chain B's state, so every bridge relies on something to attest to it: a multisig, an external validator set, a light client, a fraud-proof window, or the rollup's own proof system. Most large bridge losses have come from a failure in that verification layer: stolen validator keys, a bug that let a forged proof pass, or a bad upgrade. A bridge isn't "safe" or "unsafe" as a whole; what you need to know is what it trusts and how that can fail.
How a token bridge works
The classic design is lock-and-mint:
You lock 10 ETH in a bridge contract on chain A.
Some verifier attests to chain B that the lock happened.
The bridge contract on chain B mints 10 wrapped ETH to you.
To go back, you burn the wrapped tokens on B, and the verifier attests so the contract on A can release them.
Every wrapped token on B is an IOU backed by the pool on A. Drain the pool, or mint on B without a matching lock, and every holder of the wrapped token is left with unbacked tokens. The pool also concentrates a lot of value in one contract, which makes it an obvious target.
Variants include burn-and-mint, where the issuer controls minting on every chain (Circle's CCTP for USDC), and liquidity networks, where relayers pay you on the destination chain from their own funds.
Verification models, from most to least trust
Model
Who attests
What must go wrong
Multisig / MPC
A small set of key holders
Threshold of keys stolen or colluding
External validator set
A larger permissioned or staked set
Enough validators compromised; operator bugs
Optimistic
A single attester, disputable during a window
Attester lies and no watcher disputes in time
Light client / ZK light client
On-chain verification of the source chain's consensus
Bug in the client or proof system; source chain consensus failure
On Bitcoin, scale confirmation depth with the amount at risk, since finality is probabilistic. On Ethereum, wait for the finalized checkpoint. On rollups, wait for the batch to be final on L1.
Rollup proof system failure (inherits L1 security)
A rollup's canonical bridge (Arbitrum, OP Mainnet) is in the last row. That's why it's slow to withdraw from, and usually the safest route to Ethereum.
How bridge hacks actually happen
These well-known incidents show the main failure types.
Validator key compromise. In 2022 the Ronin bridge lost over $600 million after attackers gained control of five of its nine validator keys, enough to meet the threshold and sign fraudulent withdrawals. Harmony's Horizon bridge lost around $100 million the same year after keys in a 2-of-5 multisig were compromised. A low threshold, or keys that share infrastructure, turns one intrusion into total loss.
Verification bugs. Also in 2022, Wormhole's Solana contract accepted a spoofed account in place of the real system account it relied on to check signatures. The attacker minted about 120,000 wrapped ETH without depositing anything. Later that year, the BNB Chain token hub accepted a forged proof, and the attacker minted a large amount of BNB before validators halted the chain.
Upgrade and initialization errors. Nomad (August 2022) shipped an upgrade that effectively treated an all-zero root as trusted. Unproven messages then passed verification, and once the first exploit was public, many copycats drained the bridge by replaying the transaction with their own addresses.
Message authorization bugs. In the 2021 Poly Network incident, a crafted cross-chain message called a privileged function and replaced the keys the bridge trusted. Most of the funds were later returned.
The common thread: verification logic, privileged keys and upgrades are where one flaw unlocks the entire pool.
If your contract receives cross-chain messages
Bridge SDKs deliver messages by calling your contract. Every time, check who delivered the message, who originally sent it, whether you've seen it before, and how much damage one bad message can do.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract BridgeReceiver {
address public immutable endpoint; // bridge contract allowed to call us
uint64 public immutable srcChainId; // the only source chain we accept
address public immutable srcSender; // our own contract on that chain
uint256 public immutable maxPerHour;
uint256 public windowStart;
uint256 public releasedInWindow;
mapping(bytes32 => bool) public processed;
constructor(address _endpoint, uint64 _srcChainId, address _srcSender, uint256 _maxPerHour) {
(endpoint, srcChainId, srcSender, maxPerHour) = (_endpoint, _srcChainId, _srcSender, _maxPerHour);
}
function receiveMessage(uint64 fromChainId, address fromSender, bytes32 messageId, bytes calldata payload)
external
{
require(msg.sender == endpoint, "not endpoint"); // 1. who delivered it
require(fromChainId == srcChainId && fromSender == srcSender, "untrusted source"); // 2. who sent it
require(!processed[messageId], "replayed"); // 3. replay
processed[messageId] = true;
(address to, uint256 amount) = abi.decode(payload, (address, uint256));
if (block.timestamp >= windowStart + 1 hours) (windowStart, releasedInWindow) = (block.timestamp, 0);
releasedInWindow += amount;
require(releasedInWindow <= maxPerHour, "rate limited"); // 4. blast radius
_release(to, amount);
}
function _release(address to, uint256 amount) internal virtual {
// transfer or mint here
}
}
Function names differ between bridges, but the checks don't. Skipping check 1 or 2 is the most common integration bug: anyone can then pretend to be the bridge, or send a genuine message from their own contract on the source chain.
Evaluating a bridge before you use or integrate it
What verifies messages? Multisig threshold and key holders, validator set size, light client, or proofs.
Who can upgrade the contracts, and how fast? An instant upgrade by a small multisig can override every other guarantee. Look for timelocks.
Is there a pause and rate limit? These cap the damage when something goes wrong.
Is the wrapped token canonical? The same asset bridged by two different bridges gives you two different, non-fungible tokens with different risks.
Audits and track record. These are useful, but no guarantee. Audited bridges have been exploited too.
Independent risk write-ups, such as L2BEAT's, describe the trust assumptions for many bridges and rollups.
Checklist
Work out what verifies cross-chain messages. That's your real security assumption.
Prefer canonical rollup bridges or light-client/proof-based bridges for large amounts, and accept the slower speed.
Treat wrapped tokens as claims on a pool that can be drained.
In receivers, check endpoint, origin chain and sender, replay protection, and a rate limit.
Check upgrade keys and timelocks. Bridge only what you can afford to have at risk.
BIP-39 encodes random entropy as 12-24 words and stretches them into a seed; BIP-32/44 derive every key from it. Store the words offline on durable media in several places, never digitally.
Bitcoin tracks unspent outputs and wallets compute balances, with implicit fees and change outputs. Ethereum stores a balance and nonce per account, so nonce management replaces coin selection.