Findings
H-01High
Cross-chain replay without nonce
Description
Messages are verified by signature only. Same signed message can be relayed on multiple target chains. Attacker replays a valid withdraw on Chain B after it was already executed on Chain A.
Recommendation
Include (chainId, nonce) in signed payload. Maintain per-sender nonce on each destination chain. Reject duplicates.
Code
// Vulnerable: no chain/nonce in message
struct Message {
address sender;
address token;
uint256 amount;
bytes32 txHash;
}
// Add: uint256 destChainId; uint256 nonce;H-02High
Signature malleability
Description
Using ecrecover directly allows signature malleability (ECDSA s-value). A valid signature can be modified to a different valid signature, breaking nonce/replay assumptions.
Recommendation
Use OpenZeppelin ECDSA.recover with signature validation that rejects s > secp256k1.n/2. Or use EIP-1271 for contract signers.
Code
address signer = ecrecover(
keccak256(abi.encodePacked(prefix, messageHash)),
v, r, s
);
// s malleability: (r,s) and (r, n-s) both valid