SCWE-107: Missing Chain ID Validation in Cross-Chain Messages
Stable Version v1.0
This content is in the version-(v1.0) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).
Relationships¶
- CWE-345: Insufficient Verification of Data Authenticity
https://cwe.mitre.org/data/definitions/345.html
Description¶
Cross-chain handlers that accept payloads without checking the source chainId or endpoint domain allow replay of messages from other networks or forks. Attackers can re-trigger transfers, minting, or governance actions on unintended chains.
Remediation¶
- Bind every inbound message to an expected source chain/domain and trusted sender.
- Include
chainId/domain separators in signed payloads and verify them before execution. - Maintain replay protection (nonces) per (sourceChain, sourceSender).
Examples¶
Vulnerable¶
pragma solidity ^0.8.0;
contract BridgeReceiver {
function receiveMessage(bytes calldata data) external {
_execute(data); // no chainId/source validation
}
}
Fixed¶
pragma solidity ^0.8.0;
contract BridgeReceiver {
mapping(uint256 => mapping(address => uint256)) public nonce; // per (chainId, sender)
address public trustedSender;
uint256 public trustedChainId;
function receiveMessage(uint256 srcChainId, address src, uint256 n, bytes calldata data) external {
require(srcChainId == trustedChainId && src == trustedSender, "unauthorized source");
require(n == nonce[srcChainId][src]++, "replay");
_execute(data);
}
}