Skip to main content
Sigvex

ERC-1271 Signature Verification Remediation

How to verify signatures safely for smart-contract signers: check the magic value, support both EOA and contract signers, and guard the call.

ERC-1271 Signature Verification Remediation

Overview

Related Detector: ERC-1271 Signature Verification

ERC-1271 lets contracts (multisigs, smart accounts) validate signatures via isValidSignature(bytes32,bytes), which returns a 4-byte magic value on success. Verifiers that assume every signer is an EOA, or that ignore the magic value, either reject valid smart-account signatures or accept invalid ones. The remediation is to branch on whether the signer has code and to check the exact return value.

Before (Vulnerable)

function _check(address signer, bytes32 hash, bytes memory sig) internal view {
    // Assumes an EOA — smart-contract signers can never authorize.
    require(ECDSA.recover(hash, sig) == signer, "Bad sig");
}

After (Fixed — EOA and ERC-1271 paths, magic-value checked)

bytes4 constant MAGIC = 0x1626ba7e;   // ERC-1271 isValidSignature selector

function _check(address signer, bytes32 hash, bytes memory sig) internal view {
    if (signer.code.length == 0) {
        require(ECDSA.recover(hash, sig) == signer, "Bad EOA sig");
    } else {
        require(IERC1271(signer).isValidSignature(hash, sig) == MAGIC, "Bad 1271 sig");
    }
}

OpenZeppelin’s SignatureChecker.isValidSignatureNow implements exactly this dual path. Treat any return value other than the magic constant as failure.

Common Mistakes

  • Checking only that isValidSignature did not revert, instead of comparing the returned bytes4 to the magic value.
  • Allowing the verified contract to re-enter during isValidSignature and mutate state that the caller relies on.
  • Assuming a signature that validated once is single-use; enforce nonces/deadlines separately.

References