A bridge is a contract on one chain that locks or burns assets, and a contract on another chain that mints or releases them, with something in between that tells the second contract the first one really did its part. Every bridge drain we have studied is an attack on that "something in between". The attacker does not break the lock, and does not break the mint. They convince the mint that a lock happened when it did not, or they take control of whoever gets to say so.
Bridges are the most concentrated honeypots in Web3. The locked side holds the collateral for every wrapped asset on the destination chain, and a single forged message empties it. This article is for teams building or integrating bridges and for the people responsible for the keys behind them. We cover the designs, where each one breaks, and the controls that would have limited the damage in nearly every drain we know of.
The trust boundary is the attack surface
A contract on chain A can verify anything that happened on chain A, because it can read the state. It can verify nothing about chain B directly. Whatever carries "this happened on B" to A is the bridge's trust boundary, and it is where the attacker focuses.
The first audit question for any bridge is: what, precisely, does the destination contract check before it mints? Write the conditions down. For each, ask who or what can make it true without a corresponding lock on the source. On well-designed bridges every entry resolves to cryptographic verification of source-chain state. On badly designed bridges the list contains a signature from a server, and the server is the bridge.
A taxonomy of bridge designs
Bridges differ in what the destination trusts. We group them by that property because it determines the failure modes.
External validator sets
Off-chain nodes watch the source chain, agree that a lock happened, and sign a message; the destination checks for enough valid signatures and mints. The trust assumption is that a threshold of validator keys is honest and uncompromised. Most of the largest drains fall into this category, because the bridge's security reduces to a handful of keys, and keys are stolen with phishing and malware, not cryptanalysis.
Light clients and on-chain verification
The destination runs a light client of the source: it tracks headers, verifies the consensus signatures on each, and checks Merkle proofs of the lock event against a verified header. The trust assumption is the source chain's own consensus. This is the strongest model and the one where verification bugs are most dangerous, because there is no human in the loop to notice a forged proof.
Optimistic bridges
A relayer posts a claim about source state and a challenge window follows during which watchers can submit fraud proofs. The trust assumption is that at least one honest watcher is online and funded during every window. The failure modes are watchers that are not running, windows too short to react, and fraud-proof mechanisms that cannot express the fraud that occurred.
ZK-verified bridges
A prover generates a succinct proof that a source header is valid under the source's consensus rules and that an event is included in it; the destination verifies the proof. Trust moves to the circuit's soundness and the verifier contract. These inherit every issue in security pitfalls in zero-knowledge circuits, with the added pressure that a soundness bug in a bridge circuit is a direct path to the locked funds.
Hybrids are common. Each additional mechanism adds a way to be wrong, and we audit every path to the mint independently.
Signer-key compromise
The simplest drain and the most common. If the attacker obtains a threshold of signer keys, they sign a message releasing the entire locked balance to themselves. No contract bug is required.
How keys get taken: social engineering of operators, malware on signing machines, one hosting provider running several validators, keys generated on one machine and distributed, keys never rotated after staff left. The threshold provides less protection than it appears. A five-of-nine multisig where four signers run the same client on the same cloud account is a one-of-one.
The defences are operational: independent operators with no shared infrastructure, hardware signing, a threshold that forces real diversity, documented key ceremonies, and rotation on a schedule and on every personnel change. The contract side can then limit what a compromised quorum can do: rate limits on outflow, a delay on large withdrawals with a separate guardian veto, and validators that attest to source state rather than authorising arbitrary transfers, so a stolen quorum can only relay what actually happened.
Our test is a review of the operator set: who the signers are, where their keys live, what they share, and what happens on the contract if a threshold of them is malicious. If the answer is "everything is gone", that is the finding, however reputable the signers.
Message verification bugs
Where the bridge verifies proofs on-chain, the proof checker is the trust boundary, and a bug there is a stolen quorum.
Forged proofs and missing root checks
A Merkle proof is only meaningful against a trusted root. The classic failure is a verifier that validates the proof's internal consistency but takes the root from the message itself, or from storage the attacker can influence, instead of from an independently verified header. The attacker builds a tree containing a fake lock event, computes its root, and submits both. Every hash checks out; none of it happened.
Related failures: verifying a header's structure but not its consensus signatures, accepting a header from an unfinalised fork, and verifying inclusion in a receipts trie without checking that the emitter is the bridge contract.
Function selector and payload confusion
Some verifiers check that a message is valid but not that it is the kind of message they expect, so a proof of a transfer is accepted by a function expecting a validator-set update. Payloads parsed from raw bytes without strict length and type checks have been exploited to inject fields the sender never intended. Every message type needs a domain separator, and every parser must reject anything that is not exactly the expected shape.
Validator-set updates
The function that changes who the bridge trusts is the most privileged in the system. Bugs here include accepting an update signed by the new set rather than the old, accepting duplicate or zero addresses that satisfy the threshold count, and failing to enforce an increasing epoch so an old set can be reinstated.
How we test
For every verification path we submit messages with each check individually defeated: wrong root, unsigned header, stale epoch, mismatched emitter, oversized payload, duplicate signer. Any that does not revert is a finding. We also fuzz the parsers, because proof decoders are hand-written byte manipulation and that is where silent misparsing lives.
Replay across chains and across time
A valid message, once accepted, must never be accepted again, anywhere.
The failures: no nonce, so the same release can be submitted repeatedly; a nonce tracked per sender rather than globally, so senders collide; no destination chain ID, so a release signed for one chain is valid on every chain with the same signer set; and no destination contract address, so a release meant for a deprecated bridge version replays against the current one.
When a source chain forks, events exist on both sides, and a bridge that watches the wrong fork, or both, mints twice for one lock. Finality must be part of the bridge's verification, not an operator convention.
Our checklist: every message includes source chain, destination chain, destination contract, a globally unique nonce and a payload hash; the destination stores consumed hashes and rejects repeats; and source finality depth is enforced on-chain, not in a relayer configuration file.
Minimise what you trust
Every component in the message path is a potential point of compromise: the relayer, the header oracle, the pause admin, the upgrade key, the indexer the frontend reads. The design goal is that no single one, and ideally no small group, can cause an unbacked mint.
That means separating roles. The relayer should be able to deliver messages or not, never alter them. The pauser should not be able to mint. The upgrader should sit behind a timelock long enough for a watcher to raise the alarm and users to exit. The validator set, if there is one, should attest to source-chain facts rather than authorise transfers, so the worst a compromised quorum can do is relay a true event twice, which replay protection blocks.
We draw the trust graph for every bridge we audit: nodes are keys and contracts, edges are "can cause this to act". Then we find the smallest set of nodes whose compromise reaches the mint. If it has one element, the bridge has a single point of failure, whatever the marketing says.
Verify on-chain, not off-chain
Any check that happens in a relayer, a watcher or an API is a check the attacker bypasses by not using that service. If the real validation lives off-chain, the contract's actual rule is "accept anything with a valid signature from the relayer key".
This shows up subtly: a relayer that checks finality while the contract does not; a watcher that validates payload format while the contract parses loosely; a frontend that restricts withdrawals while the release function takes an arbitrary recipient. In each case the security property lives in a component that is not the one holding the money. The contract that mints or releases must independently verify every condition. Off-chain services may filter and accelerate, but they may not be the only place a check happens.
Rate limits and circuit breakers
Drains take minutes to execute and hours to be noticed. A rate limit converts a total loss into a bounded one; a circuit breaker converts an ongoing drain into a paused bridge.
Rate limits belong on the destination mint and the source release, per asset and per time window, sized to normal flow with headroom. An attacker with a forged message or a stolen quorum then gets one window's worth, not the vault. Transfers above the limit go into a delayed queue with a guardian veto, which costs legitimate large users some time and costs the attacker the ability to exit before anyone looks.
Circuit breakers trigger automatically on invariant violations, not on a human reading a dashboard. A pause that requires a multisig to convene at 3 a.m. is not a circuit breaker; it is a post-mortem. We check that both exist, that limits are enforced in the contract rather than the relayer, that they cannot be raised without a timelock, and that the pause path does not depend on the keys that might be compromised.
Watch the mint: the mint/burn invariant
For every asset, one equation must hold at all times: total minted on the destination equals total locked on the source minus total released, within the bounds of in-flight messages. If minted exceeds locked, the bridge has created unbacked assets and is being drained.
Anyone with a node on each chain can check this, and it is the single most valuable monitor a bridge can run. It catches signer compromise, forged proofs, replay and verification bugs alike, because every one of them produces a mint without a matching lock. A breach should trigger the on-chain circuit breaker and page a human.
Beyond the headline invariant we monitor validator-set changes, upgrade proposals, pause events, releases above a size threshold, and the gap between source finality and destination acceptance. Each moving unexpectedly is an early signal of the drain the invariant will confirm.
How we audit a bridge
A bridge engagement spans contracts on at least two chains, the off-chain components between them, and the operational setup of whoever holds the keys.
- Trust graph: we map every key, contract, and service that can influence a mint or release, and find the minimum compromise set.
- Verification review: for each path to the mint, we enumerate the checks, remove each in turn, and confirm the mint fails. Proof parsers and header verifiers get line-by-line review and fuzzing.
- Replay matrix: every message type against every deployed chain and every contract version, checking that domain separation and nonces prevent reuse.
- Key and operator review: who the signers are, what infrastructure they share, how keys were generated and rotated, and what a threshold compromise can do on-chain.
- Limits and breakers: whether rate limits exist in the contract, what they bound an attacker to, and whether the pause fires without human action.
- Invariant monitoring: whether anyone is computing minted-versus-locked continuously, and what happens when it breaks.
High and Critical findings come with a working forged message or replay against a fork of both chains. Key-management findings come with the concrete compromise set that reaches the mint.
Next steps
If you operate a bridge, compute the mint/burn invariant for every asset today and set up an independent monitor that recomputes it every block. Then draw the trust graph and count the smallest compromise set; if it is one, fix that first. If you are integrating a bridge, ask its team for both artefacts. A team that cannot produce them has not done this analysis.
For the patterns on the DeFi side of the bridge, see DeFi exploit patterns you will see again. For the full list our auditors run on every contract, see the 2026 smart contract audit checklist.
Our bridge audit scope is on the services page, and you can reach the team on Telegram.