Bridge and cross-chain vulnerabilities in disclosed reports
Bridges hold concentrated value and validate messages produced on a chain they cannot themselves verify — the highest-severity surface in the space.
- Reports indexed
- 95
- Total paid
- $1.8M
- Critical
- 1
- Largest payout
- $1.8M
A bridge is a message verifier attached to a vault. Everything that has gone wrong with bridges is one of those two halves failing: the verifier accepts a message it should not have, or the vault releases funds the verifier never authorised.
The verifier failures are the interesting ones. Merkle proofs validated against an attacker-supplied root, signature thresholds counted without deduplicating signers, guardian sets rotated without invalidating the old set, and message handlers that check the payload but not the source chain or the source contract.
The vault failures tend to be simpler and just as expensive: mint functions reachable without a corresponding lock, replay protection keyed on a value the attacker chooses, and emergency withdrawal paths whose access control was never revisited after launch.
What reviewers look for
- Proof verification against a root the caller can influence
- Signature thresholds that do not deduplicate or order signers
- Message IDs that are not globally unique across chains
- Mint authority reachable without a verified lock event
- Guardian or validator rotation that leaves the previous set valid
Curated highlights
The largest disclosed payouts in this group, with our own summary of each. Every report links back to the original disclosure.
Bridge withdrawal proof accepts empty Merkle path
A flawed proof verification mechanism in an L2 canonical bridge contract permitted withdrawal validation using an empty Merkle proof array. When no proof elements were supplied, the verification function failed to iterate and directly compared the unhashed withdrawal leaf against the target root. By matching a fake withdrawal leaf payload with a valid historical or relayable state root, an attacker could forge arbitrary withdrawal events and drain escrowed funds from the bridge.
The Graph: If L1GraphTokenGateway's `outboundTransfer` is called by a contract, the entire `msg.value` is blackholed, whether the ticket got redeemed or not
The Graph's L1GraphTokenGateway.outboundTransfer, when bridging GRT to Arbitrum, passes the caller's own address as both the submission-refund and value-refund destination for the underlying retryable ticket. This is harmless for EOA callers because Ethereum and Arbitrum addresses are congruent, but a contract caller (e.g., a multisig) typically has no L2 counterpart able to withdraw the refund, permanently stranding the excess submission fee. The judge ruled this a Medium value-leak (not direct theft), noting the L2 ticket-creation-failure path no longer applies under Arbitrum Nitro but the refund-stranding behavior for contracts remains real.
Centrifuge Protocol V3.1: Stranded ETH on batched `crosschainTransferShares` call
Centrifuge's VaultRouter exposes a payable crosschainTransferShares function that silently zeroes out msg.value whenever the gateway is in batching mode. In that batched path the gateway is already funded separately, so the router neither forwards nor refunds the attached ETH, leaving it stranded in the router balance with only a privileged, attribution-free sweep as recovery. The condition is reachable through a normal deposit-plus-bridge batch flow, making it a repeatable loss path for users who attach value to what appears to be a benign call. The accepted fix adds an ETHNotAcceptedInBatch guard that reverts whenever batching is active and value is attached, so no ETH can be silently trapped.
Centrifuge Protocol V3.1: `Gateway.withBatch()` lacks message count validation enabling permanent DOS via an excessive number of messages in a batch
Centrifuge's cross-chain Gateway allows anyone to call withBatch() and collect an unbounded number of messages into a single outbound batch, with no validation on message count. An attacker can bundle hundreds of cheap UntrustedContractUpdate messages together with critical ones such as UpdateHoldingAmount. On the receiving chain, Gateway.handle() loops through every message, and the cumulative gas cost exceeds the block gas limit, so the whole batch reverts and becomes permanently stuck because the protocol has no split or skip mechanism. This permanently blocks pool holding-amount synchronization and spoke-to-spoke share transfers. The fix, merged in PR #43, adds a governance-configurable maxBatchMessages limit enforced during _endBatching().
Malda: Unenforced maxFee and ttl Parameters in sendMsg Function
Malda's EverclearBridge.sendMsg forwards decoded cross-chain intent parameters to everclearFeeAdapter.newIntent without enforcing that maxFee and ttl are both zero, which the Everclear netting pathway requires. A rebalancer (the privileged caller) can therefore create intents with non-zero maxFee/ttl that get misrouted to the solver pathway, which is unsupported at launch. The concrete consequences are potential denial-of-service on cross-chain liquidity rebalancing, unexpected solver fees, and forfeited netting cost savings, rather than direct token theft. Sherlock upheld the issue as medium and the protocol team fixed it in pull request #143 by adding require checks for both fields.
Malda: If Across Bridging fails, all funds intended for bridging will become locked
Malda's Rebalancer contract integrates the Across bridging protocol by setting itself as the depositor when calling depositV3Now. Across's documented behavior is to refund expired or unfilled deposits to the depositor back on the origin chain, which in this integration is the Rebalancer itself. Because the Rebalancer has no code path to route those returned tokens back into the lending market, any failed bridging attempt permanently strands the funds. The finding was validated by the Sherlock judge and fixed via a rescue helper in PR #126.
All reports in this group
- Malda: Rebalancer can steal funds from markets by sending to custom receiver through Everclear BridgeBridge exploit$0
- Malda: Rebalancer can send to unallowed destination chains through EverclearBridgeBridge exploit$0
- DODO Cross-Chain DEX: Attacker can steal an high-value token due to lack of swap executionBridge exploit$0
- DODO Cross-Chain DEX: Improper ETH Refund Handling in GatewaySend.onRevert()Bridge exploit$0
- DODO Cross-Chain DEX: GatewayTransferNative does not collect platform fee when native asset is bridgedBridge exploit$0
- ZetaChain Cross-Chain: Incorrect Formate for transaction building, and transaction executions In Solana will lead to revert all execute Operations.Bridge exploit$0
- ZetaChain Cross-Chain: Malicious observer can block messages added through the inbound trackerBridge exploit$0
- ZetaChain Cross-Chain: Malicious observer can drain Solana bridge by adding failed deposit transaction to inbound trackerBridge exploit$0
- Chakra: Invalid token address used in `ChakraSettlementHandler::cross_chain_erc20_settlement(...)` leading to invalid transaction creation and event emissionBridge exploit$0
- Chakra: Forcing Starknet handlers to be whitelisted on the same chain allows exploit of `BurnUnlock` mode to drain handler fundsBridge exploit$0
- Chakra: The `LockMint` and `BurnUnlock` modes cannot be usedBridge exploit$0
- Chakra: Does not check if `to_chain` and `to_handler` is whitelisted in `cross_chain_erc20_settlement`Bridge exploit$0
- Chakra: In Starknet, already processed messages can be re-submitted and by anyoneBridge exploit$0
- Chakra: Permanent loss of user tokens on both chains if `BurnUnlock` mode fails because of flawed burning patternBridge exploit$0
- Chakra: Wrong usage of transaction originator address instead of caller addressBridge exploit$0
- Chakra: Inconsistency in sender address when creating cross chain messages on Starknet can lead to loss of fundsBridge exploit$0
- Chakra: Handler's `receive_cross_chain_callback()` will always set the `tx_status` to `SETTLED` on source chain & burn the tokens (MintBurn Mode) even when the msg fails on destinationBridge exploit$0
- Chakra: Bridging from Starknet to Starknet causes mismatch between minted ckrBTC and BTC transferred to MuSig2Bridge exploit$0
- Chakra: In `settlement.cairo::receive_cross_chain_msg` - the `payload_type` can be passed by the user, confusing offchain systemsBridge exploit$0
- Chakra: A cross-chain message can be initiated with invalid parametersBridge exploit$0
- Thanos L2 Native Token Bridge: L1 contract can evade aliasing, spoofing unowned L2 addressBridge exploit$0
- Flayer: `ERC721Bridgable` and `ERC1155Bridgable` are not EIP-2981 compliant, and fail to correctly collect or attribute royalties to artistsBridge exploit$0
- ZetaChain: Inbound transactions submitted to the `InTxTracker` that contain multiple `ZetaSent` and `Deposited` events are not processed correctly by the observers resulting in a loss of fundsBridge exploit$0
- Olas: The `msg.value - cost` for multiple cross-chain bridges are not refunded to usersBridge exploit$0
- Olas: Attacker can make claimed staking incentives irredeemable on Gnosis ChainBridge exploit$0
- Olas: Users will lose all ETH sent as `cost` parameter in transactions to and from OptimismBridge exploit$0
- Olas: The `refundAccount` is erroneously set to `msg.sender` instead of `tx.origin` when `refundAccount` specified as `address(0)`Bridge exploit$0
- Olas: Refunds for unconsumed gas will be lost due to incorrect refund chain IDBridge exploit$0
- Olas: Loss of incentives if total weight in an epoch is zeroBridge exploit$0
- Illuminex: A malicious/ inactive relayer of VaultBitcoinWallet can make withdrawal mechanism stuck foreverBridge exploit$0
- Arbitrum Foundation: Inconsistent sequencer unexpected delay in DelayBuffer may harm users calling `forceInclusion()`Bridge exploit$0
- zkSync: User might be able to double withdraw during migrationBridge exploit$0
- zkSync: L2SharedBridge l1LegacyBridge is not setBridge exploit$0
- Tapioca DAO: Incorrect return value of function `BaseTapiocaOmnichainEngine._payNative()`Bridge exploit$0
- Taiko: A recalled ERC20 bridge transfer can lock tokens in the bridgeBridge exploit$0
- Taiko: Malicious caller of `processMessage()` can pocket the fee while forcing `excessivelySafeCall()` to failBridge exploit$0
- Taiko: Bridged tokens would be lost if sender and receiver are contracts that don't implement fallback/receiveBridge exploit$0
- Optimism Fault Proofs: Incorrect game type can be proven and finalized due to unsafe castBridge exploit$0
- Decent: Permanent loss of tokens if swap data gets outdatedBridge exploit$0
- Decent: Potential loss of capital due to fixed fee calculationsBridge exploit$0
- Decent: DecentEthRouter.sol#_bridgeWithPayload() - Any refunded ETH (native token) will be refunded to the DecentBridgeAdapter, making them stuckBridge exploit$0
- Decent: Due to missing checks on minimum gas passed through LayerZero, executions can fail on the destination chainBridge exploit$0
- Most Aleph Zero Bridge: Inconsistency in Handling WETH in `eth::most::receiveRequest`Bridge exploit$0
- Tapioca: USDO’s MSG_TAP_EXERCISE compose messages where exercised options must be withdrawn to another chain will always fail due to wrongly requiring sendParam's to address to be whitelisted in the ClusterBridge exploit$0
- Tapioca: All ETH can be stolen during rebalancing for `mTOFTs` that hold nativeBridge exploit$0
- Tapioca: Unverified `_srcChainSender` parameter allows to impersonate the senderBridge exploit$0
- Tapioca: Withdrawing to other chain when exercising options won’t work as expected, leading to DoSBridge exploit$0
- zkSync: `Mailbox.requestL2Transaction()` checks the deposit limit of `msg.sender` (`L1WethBridge`) instead of the real depositor of weth from L1, as a result, after certain time, nobody will be able to deposit weth anymore from L1Bridge exploit$0
- Olas: Withdraw amount returned by `getLiquidityAmountsAndPositions` may be incorrectBridge exploit$0
- Olas: Possible DOS when withdrawing liquidity from Solana LockboxBridge exploit$0
- Maia DAO: No deposit cross-chain calls/communication can still originate from a removed branch bridge agentBridge exploit$0
- Maia DAO: Redeeming a Settlement won't work for unsigned messages when the communicating dApps have different addresses on the different chainsBridge exploit$0
- Maia DAO: `addGlobalToken()` `localAdress` could be overwrittenBridge exploit$0
- Maia DAO: Incorrect flag results to `_hasFallbackToggled` always set to false on `createMultipleSettlement`.Bridge exploit$0
- Maia DAO: `ArbitrumBranchBridgeAgent::_performFallbackCall` function does not refund users their excess native gas depositBridge exploit$0
- Maia DAO: When using BaseBranchRouter as a router on the 'Arbitrum' branch, we are unable to invoke the 'callOutAndBridge' function.Bridge exploit$0
- Maia DAO: If `RootBridgeAgent.lzReceiveNonBlocking` reverts internally, the native token sent by relayer to RootBridgeAgent is left in RootBridgeAgentBridge exploit$0
- Maia DAO: Message channels can be blocked resulting in DoSBridge exploit$0
- Maia DAO: `BaseBranchRouter._transferAndApproveToken` may revert in some casesBridge exploit$0
- Maia DAO: Depositors could lose all their deposited tokens (including the hTokens) if their address is blacklisted in one of all the deposited underlyingTokensBridge exploit$0
- Tapioca DAO: TOFT in (m)TapiocaOft contracts can be stolen by calling removeCollateral() with a malicious removeParams.marketBridge exploit$0
- Tapioca DAO: Attacker can block LayerZero channel due to missing check of minimum gas passedBridge exploit$0
- Tapioca DAO: Refund mechanism for failed cross-chain transactions does not workBridge exploit$0
- Tapioca DAO: TOFT `removeCollateral` can be used to steal all the balanceBridge exploit$0
- Tapioca DAO: `_sendToken` implementation in `Balancer.sol` is wrong which will make the underlying erc20 be send to a random address and lostBridge exploit$0
- Tapioca DAO: All assets of (m)TapiocaOFT can be stealed by depositing to strategy cross chain call with 1 amount but maximum shares possibleBridge exploit$0
- Tapioca DAO: `multiHopSellCollateral()` will fail due to call on an invalid market address causing bridged collateral to be locked upBridge exploit$0
- Tapioca DAO: TOFT `triggerSendFrom` can be used to steal all the balanceBridge exploit$0
- Tapioca DAO: Attacker can pass duplicated reward token addresses to steal the reward of contract `twTAP.sol`Bridge exploit$0
- Centrifuge: `onlyCentrifugeChainOrigin()` can't require `msg.sender` equal `axelarGateway`Bridge exploit$0
- Maia DAO Ecosystem: Inconsistencies in reading the encoded parameters received in the `_sParams` argument in `BranchBridgeAgent::clearTokens()`Bridge exploit$0
- Maia DAO Ecosystem: `BranchBridgeAgent._normalizeDecimalsMultiple` will always revert because of the lack of allocating memoryBridge exploit$0
- Maia DAO Ecosystem: Incorrect accounting logic for `fallback` gas will lead to insolvencyBridge exploit$0
- Maia DAO Ecosystem: Replenishing gas is missing in `_payFallbackGas` of `RootBridgeAgent`Bridge exploit$0
- Maia DAO Ecosystem: An attacker can steal Accumulated Awards from `RootBridgeAgent` by abusing `retrySettlement()`Bridge exploit$0
- Maia DAO Ecosystem: Accessing the incorrect offset to get the nonce when a flag is 0x06 in `RootBridgeAgent::anyExecute()` will lead to marked as executed incorrect nonces and could potentially cause a DoSBridge exploit$0
- Maia DAO Ecosystem: Lack of a return value handing in `ArbitrumBranchBridgeAgent._performCall()` could cause users' deposit to be locked in contractBridge exploit$0
- Maia DAO Ecosystem: Depositing gas through `depositGasAnycallConfig` should not withdraw the `nativeToken`Bridge exploit$0
- Maia DAO Ecosystem: User may underpay for the remote call `ExecutionGas` on the root chainBridge exploit$0
- Maia DAO Ecosystem: Missing the unwrapping of native token in `RootBridgeAgent.sweep()` causes fees to be stuckBridge exploit$0
- Maia DAO Ecosystem: Multiple issues with `retrySettlement()` and `retrieveDeposit()` will cause loss of users' bridging depositsBridge exploit$0
- Maia DAO Ecosystem: When the `anyExecute` call is made to `RootBridgeAgent` with a `depositNonce` that has been recorded in `executionHistory`, `initialGas` and `userFeeInfo` will not be updated, which would affect the next caller of `retrySettlement`.Bridge exploit$0
- Maia DAO Ecosystem: `RootBridgeAgent->CheckParamsLib#checkParams` does not check that `_dParams.token` is underlying of `_dParams.hToken`Bridge exploit$0
- Maia DAO Ecosystem: On Ulysses omnichain - `RetrieveDeposit` might never be able to trigger the `Fallback` functionBridge exploit$0
- Maia DAO Ecosystem: Due to inadequate checks, an adversary can call `BranchBridgeAgent#retrieveDeposit` with an invalid `_depositNonce`, which would lead to a loss of other users' deposits.Bridge exploit$0
- Maia DAO Ecosystem: Multiple issues with decimal scaling will cause incorrect accounting of hTokens and underlying tokensBridge exploit$0
- Maia DAO Ecosystem: The user is enforced to overpay for the `fallback` gas when calling `retryDeposit`Bridge exploit$0
- Maia DAO Ecosystem: Incorrectly reading the offset from the received data parameter to get the `depositNonce` in the `BranchBridgeAgent::anyFallback()` functionBridge exploit$0
- Maia DAO Ecosystem: Cross-chain messaging via `Anycall` will failBridge exploit$0