Skip to content

Signature Missing Domain / chainid — Cross-Chain Replay

SAFE-0114 Signatures Checked automatically by the scanner
1

What goes wrong

The signed digest omits an EIP-712 domain separator with block.chainid and the verifying contract address. A signature valid on one chain (or on a fork) is replayable on another chain where the same contract is deployed.

2

The vulnerable pattern

proof of concept — how it is exploited
// same contract on Ethereum + Polygon, digest has no chainid.
// user signs a withdrawal on mainnet; attacker replays the exact bytes
// on Polygon and withdraws there too.
3

How to fix it

the pattern that is safe
bytes32 DOMAIN = keccak256(abi.encode(
  keccak256("EIP712Domain(...,uint256 chainId,address verifyingContract)"),
  ..., block.chainid, address(this)));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN, structHash));
EIP-712 domain must bind chainid + verifyingContract.
Check your own contract for this

The SaferICO scanner runs 201 detectors over your Solidity source, SAFE-0114 among them. Paste an address or the source itself — a small per-scan fee, shown before you sign, or unlimited on any plan.

Run the scanner See how it is attacked Read the docs