Audit the Bridge: Three Critical Flaws
You've been hired to audit a new cross-chain bridge contract before mainnet launch. The team provided a simplified 200-line Solidity snippet of their merkle-proof verification system. They claim it's bulletproof.
Contract excerpt (key functions):
soliditycontract SimpleBridge { mapping(bytes32 => bool) public processedRoots; address public operator; function submitRoot(bytes32 root, bytes memory signature) external { require(recoverSigner(root, signature) == operator); processedRoots[root] = true; } function withdraw(bytes32[] memory proof, bytes32 leaf, uint256 amount, address recipient) external { bytes32 computedRoot = leaf; for (uint i = 0; i < proof.length; i++) { if (computedRoot < proof[i]) { computedRoot = keccak256(abi.encodePacked(computedRoot, proof[i])); } else { computedRoot = keccak256(abi.encodePacked(proof[i], computedRoot)); } } require(processedRoots[computedRoot], "Invalid proof"); payable(recipient).transfer(amount); } function recoverSigner(bytes32 hash, bytes memory sig) internal pure returns (address) { (uint8 v, bytes32 r, bytes32 s) = splitSignature(sig); return ecrecover(hash, v, r, s); } }
Additional context: The bridge operator signs merkle roots off-chain. Users submit proofs to claim funds. The leaf format is keccak256(abi.encodePacked(amount, recipient)).
Your task: Identify the three critical vulnerabilities. The first allows double-withdrawal, the second enables operator key bypass, the third permits merkle tree forgery. Combine the bug names (no spaces, alphabetical order, underscores between) as your flag.
Bug taxonomy: replay_attack, malleable_signature, empty_proof_acceptance, leaf_injection, missing_nonce, unchecked_ecrecover
The three present are a subset of the six listed above.