
// Bridge.sol - Vulnerable bridge contract
contract Bridge {
mapping(bytes32 => bool) public processed;
event Deposited(address from, address to, uint256 amount, uint256 chainId);
function deposit(address to, uint256 amount, uint256 chainId) external payable {
emit Deposited(msg.sender, to, amount, chainId);
}
function withdraw(bytes memory proof, address from, address to, uint256 amount, uint256 chainId) external {
// Verify proof signature (simulated)
require(verifyProof(proof, from, to, amount, chainId), "Invalid proof");
// Missing check: did this message originate from chainId?
// An attacker can replay a Deposit event from another chain where they are the 'from'
payable(to).transfer(amount);
}
function verifyProof(...) internal pure returns (bool) { return true; } // simplified
}
跨链桥验证消息证明,但不检查源链的链 ID。攻击者可以将来自低安全性链的存款事件重放到主桥上,从而凭空铸造代币。
withdraw 函数从证明中接受 chainId 参数,但未验证其是否与预期源链匹配;证明仅对消息签名,并未对链上下文签名。部署存在漏洞的合约,在测试链上模拟一次存款,然后在主链上用相同的证明调用 withdraw——代币即被释放。
git clone https://github.com/yourorg/CVE-2026-23003.git
cd CVE-2026-23003
# Deploy with Hardhat/Foundry and test