Skip to content
Security
Skill

/signature-replay-analysis

Detects signature replay vulnerabilities in smart contracts — affecting 19.63% of signature-using contracts. Covers five replay types (same-chain, cross-chain, cross-contract, nonce-skip, expired-signature), EIP-712 domain separator verification, nonce management analysis,

BOOST
From plugin
quillshield-skills
12911 skills
Install
$ npx -y skills add quillai-network/quillshield_skills --skill signature-replay-analysis --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/signature-replay-analysis

Context preview

The summary Claude sees to decide when to auto-load this skill.

Detects signature replay vulnerabilities in smart contracts — affecting 19.63% of signature-using contracts. Covers five replay types (same-chain, cross-chain, cross-contract, nonce-skip, expired-signature), EIP-712 domain separator verification, nonce management analysis,

SKILL.md

signature-replay-analysis.SKILL.md
name: signature-replay-analysis
description: Detects signature replay vulnerabilities in smart contracts — affecting 19.63% of signature-using contracts. Covers five replay types (same-chain, cross-chain, cross-contract, nonce-skip, expired-signature), EIP-712 domain separator verification, nonce management analysis, ecrecover edge cases (address(0), malleability, s-value), permit/permit2 safety, ERC-1271 contract wallet support, and meta-transaction security. Use when auditing contracts with ecrecover, ECDSA, EIP-712, permit, meta-transactions, multi-sig, or any off-chain signature verification.

Signature & Replay Analysis

Detect vulnerabilities where **cryptographic signatures can be reused**, replayed across chains/contracts, or exploited through implementation flaws. Research shows 19.63% of Ethereum contracts using signatures contain replay vulnerabilities.

When to Use

  • Auditing contracts that verify signatures (`ecrecover`, ECDSA, EIP-712)
  • Reviewing ERC-20 `permit()` / Uniswap Permit2 implementations
  • Analyzing meta-transaction / gasless relay systems
  • Verifying multi-sig signature aggregation
  • Checking off-chain order books or signed message execution

When NOT to Use

  • Contracts without any signature verification
  • Pure on-chain access control (use semantic-guard-analysis)
  • Token standard compliance (use external-call-safety)

Core Concept: The Signature Trust Model

A signature proves that a specific private key holder authorized a specific action. For this to be secure, the signature must be:

1. **Bound to context** — specific chain, contract, and version (domain separation) 2. **Used exactly once** — nonce prevents replay 3. **Time-limited** — deadline/expiry prevents late execution 4. **Correctly verified** — ecrecover edge cases handled

Any gap in this model creates a replay vulnerability.

The Five Replay Types

Type 1: Same-Chain Replay

The exact same signature is submitted multiple times to the same contract on the same chain.

// VULNERABLE: No nonce — same signature works forever
function executeWithSig(address to, uint256 amount, bytes memory signature) external {
    bytes32 hash = keccak256(abi.encodePacked(to, amount));
    address signer = ECDSA.recover(hash, signature);
    require(signer == admin, "Invalid signer");
    token.transfer(to, amount);
    // Attacker can submit this same signature again and again!
}

// SAFE: Use nonce
mapping(address => uint256) public nonces;

function executeWithSig(address to, uint256 amount, uint256 nonce, bytes memory signature) external {
    require(nonce == nonces[admin], "Invalid nonce");
    bytes32 hash = keccak256(abi.encodePacked(to, amount, nonce));
    address signer = ECDSA.recover(hash, signature);
    require(signer == admin, "Invalid signer");
    nonces[admin]++;
    token.transfer(to, amount);
}

Type 2: Cross-Chain Replay

A signature valid on one chain (e.g., Ethereum) is replayed on another chain (e.g., Polygon, Arbitrum) where the same contract is deployed.

// VULNERABLE: No chainId in signed message
bytes32 hash = keccak256(abi.encodePacked(to, amount, nonce));
// This hash is identical on Ethereum, Polygon, Arbitrum, etc.

// SAFE: Include chainId (via EIP-712 domain separator)
bytes32 DOMAIN_SEPARATOR = keccak256(abi.encode(
    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
    keccak256(bytes("MyContract")),
    keccak256(bytes("1")),
    block.chainid,
    address(this)
));

Type 3: Cross-Contract Replay

A signature for Contract A is replayed on Contract B (same chain) if both accept the same message format without contract-specific binding.

// VULNERABLE: No contract address in signed message
bytes32 hash = keccak256(abi.encodePacked(to, amount, nonce, block.chainid));
// Same hash for any contract on this chain

// SAFE: Include verifyingContract (via EIP-712)
// The domain separator includes address(this), binding to this specific contract

Type 4: Nonce-Skip Replay

Nonce implementation allows gaps or out-of-order execution, enabling skipped nonces to be replayed later.

// VULNERABLE: Bitmap nonce without invalidation
mapping(uint256 => bool) public usedNonces;

function execute(uint256 nonce, ...) external {
    require(!usedNonces[nonce], "Used");
    usedNonces[nonce] = true;
    // If nonces 1, 2, 3 are used but 4 is skipped,
    // nonce 4 can be used anytime in the future
    // This may be intentional OR a vulnerability depending on context
}

// SAFER for strict ordering: Sequential nonce
mapping(address => uint256) public nonces;

function execute(uint256 nonce, ...) external {
    require(nonce == nonces[signer], "Invalid nonce");
    nonces[signer]++;
}

Type 5: Expired-Signature Replay

A signature without a deadline can be held and executed at an arbitrary future time when conditions have changed.

// VULNERABLE: No deadline — signature valid forever
function permit(address owner, address spender, uint256 value, uint8 v, bytes32 r, bytes32 s) external {
    bytes32 hash = keccak256(abi.encodePacked(owner, spender, value, nonces[owner]++));
    require(ecrecover(hash, v, r, s) == owner, "Invalid");
    allowance[owner][spender] = value;
    // This permit can be executed weeks later when user doesn't expect it
}

// SAFE: Include deadline
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
    require(block.timestamp <= deadline, "Expired");
    // ... rest of verification
}

ecrecover Safety

Edge Case 1: Returns address(0)

`ecrecover` returns `address(0)` for invalid signatures instead of reverting.

// VULNERABLE: address(0) accepted as valid signer
address signer = ecrecover(hash, v, r, s);
require(signer == owner, "Invalid");
// If owner == address(0) AND signature is invalid → passes!

// SAFE: Explicit
Read more
Ships withquillshield-skills

AI agent skills for advanced smart contract security auditing. These skills teach AI agents (Claude, Cursor) the QuillShield methodology for detecting vulnerabilities that traditional static analysis tools miss.

Get the whole plugin

Other skills on quillshield-skills.