# Nomad Bridge: zero root bypasses message verification

Nomad Bridge Replica initialized with zero committedRoot, making any message hash acceptable; attackers drained ~$190M by replaying calldata with swapped recipient.

- Payout: Real-world hack
- Severity: critical
- Program: Nomad Bridge
- Analysis by: DeFiHackLabs
- Disclosed: 2022-08-02
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-08/NomadBridge_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20220802-nomadbridge
- Tags: area:web3 domain:web3 impact:funds-loss impact:mass-exploit kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity vuln:access-control vuln:business-logic

**Target:** Nomad Bridge Replica contract on Ethereum
**Root cause:** Replica contract was initialized with committedRoot set to zero, and acceptableRoot(0) returned true because confirmAt[0] was set to 1, allowing any message with unproven root (zero) to be processed.
**Steps:**
1. Call `Replica.process(_message)` with an arbitrary message where the message hash maps to root 0x0.
2. Inside process, `acceptableRoot(messages[_messageHash])` returns true because root 0 is acceptable.
3. Message is proved and tokens are transferred to the attacker-specified recipient.
4. Copy original attacker's calldata and replace recipient address with your own to drain funds.
**How found:** Likely discovered by observing the initialization transaction where committedRoot was set to zero, or by noticing that any message with zero root could be processed after the upgrade.
**Exploitation:** Attacker calls process with crafted message containing transfer of 100 WBTC to their address; verification bypassed due to zero root; bridge releases funds. Others copy the transaction calldata, replacing the recipient address, to drain remaining assets in a frenzy.
**Escalation:** After initial exploit, many attackers and bots replicated the transaction by copying calldata and changing the recipient, draining nearly all bridge funds within hours.
**Insight:** Check initialization parameters of upgradeable contracts, especially zero-value roots or addresses that may bypass validation; monitor on-chain for unusual initialization transactions.

## Proof of concept (copied exactly from the original report)

**Forged message bytes with attacker recipient**

```
bytes memory msgP1 =
            hex"6265616d000000000000000000000000d3dfd3ede74e0dcebc1aa685e151332857efce2d000013d60065746800000000000000000000000088a69b4e698a4b090df6cf5bd7b2d47325ad30a3006574680000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c59903000000000000000000000000";
        bytes memory recvAddr = abi.encodePacked(address(this));
        bytes memory msgP2 =
            hex"00000000000000000000000000000000000000000000000000000002540be400e6e85ded018819209cfb948d074cb65de145734b5b0852e4a5db25cac2b8c39a";
        bytes memory _message = bytes.concat(msgP1, recvAddr, msgP2);
```

