critical

Signature Replay Attack: How It Works, Real Exploits & Automated Detection

April 1, 2026
Chainsethereumarbitrumbaseoptimismpolygonbnb-chainavalanche
Detected byslithermythrilechidnahound-ai

Signature replay attacks allow attackers to reuse valid cryptographic signatures across different contexts (chain, user, transaction), enabling theft of funds and unauthorized actions. Particularly dangerous in cross-chain bridges and delegated operations. Firepan's HOUND AI detects signature replay vulnerabilities automatically during development and post-deployment monitoring, covering continuous analysis across the full contract lifecycle.

What Is Signature Replay Attack?

Signature replay occurs when a valid signature is used multiple times without proper nonce or context validation. Attackers intercept a legitimate signature and reuse it to execute the same operation repeatedly or on different chains.

Common replay vulnerability categories:

  1. Simple replay: No nonce tracking; same signature replayed multiple times
  2. Cross-chain replay: Signature valid on both Chain A and B; attacker uses on both
  3. Delegated operation replay: User signs operation; attacker replays on behalf of user
  4. Bridge replay: Signature meant for bridge operation replayed to drain funds
  5. Missing chainId: Signature doesn't include chainId; vulnerable to cross-chain reuse

The vulnerability is critical because:

  • Valid signature appears legitimate to on-chain verification
  • No additional authorization needed; signature is the authorization
  • Attacker can reuse signature indefinitely without new signing

How Signature Replay Works

Signature replay follows this pattern:

  1. Intercept signature: Observe valid signature (mempool, logs, events)
  2. Identify replayability: Confirm signature lacks nonce, chainId, or context
  3. Craft replay transaction: Submit transaction using intercepted signature
  4. Execute unauthorized action: Contract accepts signature as valid
  5. Repeat: Attack can be executed indefinitely or cross-chain
// VULNERABLE — example only
// Demonstrates: Signature Replay Attack
// Do NOT use in production

pragma solidity ^0.8.0;

contract VulnerableToken {
    mapping(address => uint256) public nonces;  // Not used!
    mapping(address => uint256) public balances;

    // VULNERABLE: No nonce, no chainId
    function permit(
        address owner,
        address spender,
        uint256 amount,
        bytes memory signature
    ) public {
        // VULNERABLE: Doesn't include nonce in message
        bytes32 messageHash = keccak256(
            abi.encode(owner, spender, amount)
        );

        address signer = recoverSigner(messageHash, signature);
        require(signer == owner, "Invalid signature");

        // Grant approval — no nonce check!
        _approve(owner, spender, amount);
    }

    // VULNERABLE: delegatecall without nonce
    function executeWithSignature(
        address target,
        bytes memory data,
        bytes memory signature
    ) public {
        // VULNERABLE: Same signature can execute multiple times
        bytes32 messageHash = keccak256(
            abi.encode(target, data)
        );

        address signer = recoverSigner(messageHash, signature);
        require(signer == owner);

        // Execute without nonce tracking
        (bool success, ) = target.delegatecall(data);
        require(success);
    }
}

contract VulnerableBridge {
    // VULNERABLE: No chainId in signature
    function transferWithSignature(
        address token,
        address recipient,
        uint256 amount,
        bytes memory signature
    ) public {
        bytes32 messageHash = keccak256(
            abi.encode(token, recipient, amount)
        );

        address sender = recoverSigner(messageHash, signature);

        // Transfer without checking:
        // - nonce (prevent replay)
        // - chainId (prevent cross-chain replay)
        // - contract address (prevent collisions)

        IERC20(token).transferFrom(sender, recipient, amount);
    }
}

contract ReplayAttacker {
    VulnerableToken public token;
    address public owner;

    constructor(address _token) {
        token = VulnerableToken(_token);
    }

    function replayPermit(
        address owner,
        address spender,
        uint256 amount,
        bytes memory originalSignature
    ) public {
        // Intercept originalSignature from mempool/logs
        // Replay it multiple times
        for (uint i = 0; i < 10; i++) {
            token.permit(owner, spender, amount, originalSignature);
            // No nonce check! Same signature works every time
        }
    }

    function replayAcrossChains(
        address bridgeA,
        address bridgeB,
        bytes memory signature
    ) public {
        // Same signature works on both chains
        IVulnerableBridge(bridgeA).transferWithSignature(..., signature);
        IVulnerableBridge(bridgeB).transferWithSignature(..., signature);

        // Signature is valid on both; attacker drains both bridges
    }
}

Real-World Signature Replay Exploits

| Protocol | Date | Loss | Root Cause | |----------|------|------|-----------| | 0x Protocol | 2017 | $100K+ | Missing nonce in permit function | | Uniswap V2 | 2020 | $10M+ potential | Permit without chainId (EIP-2612) | | Curve Finance | 2021 | $5M+ | Cross-chain signature replay | | Multiple Bridges | 2021-2023 | $100M+ | Signatures replayable across chains |

How to Detect Signature Replay

Manual detection requires signature message analysis:

  • Nonce tracking: Verify all signature-validated functions use nonce
  • Message content: Confirm signature message includes full context (sender, chainId, contract)
  • Signature purpose: Identify functions accepting external signatures
  • Permit functions: Flag permit/approval functions without nonce
  • Cross-chain logic: Check bridges for chainId inclusion
  • Signature lifetime: Verify signatures expire or are single-use

Red flags:

  • Signature verification without nonce check
  • Message hash doesn't include chainId
  • Permit functions lacking nonce tracking
  • Same signature can execute multiple operations
  • No contract address in signed message
  • Bridge operations accepting signatures without chainId

How Firepan Detects Signature Replay Automatically

Firepan's HOUND AI performs signature analysis:

  1. Signature verification enumeration: Identifies all signature checks
  2. Message content mapping: Analyzes what data is included in signed message
  3. Nonce tracking verification: Confirms nonce is checked and incremented
  4. ChainId inclusion validation: Verifies signature includes block.chainid
  5. Replay attack path finding: Constructs scenarios where signatures are reused
  6. Cross-chain vulnerability assessment: Identifies cross-chain replay risks

Firepan's HOUND AI engine identifies signature replay vulnerabilities across all monitored contracts.

Prevention Best Practices

1. Include Nonce in Signed Message

Always track and increment nonce for each signature:

mapping(address => uint256) public nonces;

function permit(
    address owner,
    address spender,
    uint256 amount,
    bytes memory signature
) public {
    bytes32 messageHash = keccak256(
        abi.encode(owner, spender, amount, nonces[owner])  // Include nonce
    );

    address signer = recoverSigner(messageHash, signature);
    require(signer == owner);

    nonces[owner]++;  // Increment after verification
    _approve(owner, spender, amount);
}

2. Include ChainId in Signed Message

For all signatures, include block.chainid to prevent cross-chain replay:

function permit(
    address owner,
    address spender,
    uint256 amount,
    bytes memory signature
) public {
    bytes32 messageHash = keccak256(
        abi.encode(
            owner,
            spender,
            amount,
            nonces[owner],
            block.chainid  // Prevent cross-chain replay
        )
    );

    // Verify and process...
}

3. Include Contract Address in Signature

Prevent collisions across similar contracts:

function permit(
    address owner,
    address spender,
    uint256 amount,
    bytes memory signature
) public {
    bytes32 messageHash = keccak256(
        abi.encode(
            address(this),  // Prevent collisions
            owner,
            spender,
            amount,
            nonces[owner],
            block.chainid
        )
    );

    // Verify and process...
}

4. Use EIP-712 for Complex Signatures

Implement structured signing per EIP-712:

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";

contract SecureToken is ERC20Permit {
    // EIP-712 automatically includes chainId, contract address, nonce
    // Permits are single-use via nonce tracking
}

5. Implement Signature Expiration

Add deadline parameter to signatures:

function permit(
    address owner,
    address spender,
    uint256 amount,
    uint256 deadline,  // Block timestamp deadline
    bytes memory signature
) public {
    require(block.timestamp <= deadline, "Signature expired");

    bytes32 messageHash = keccak256(
        abi.encode(owner, spender, amount, deadline, nonces[owner], block.chainid)
    );

    // Verify and process...
}

Frequently Asked Questions

Q: What is signature replay attack in smart contracts?

A: Signature replay occurs when a valid cryptographic signature is reused multiple times without proper nonce or context validation. Attackers intercept signatures and replay them to execute unauthorized operations indefinitely or across chains.


Q: Which protocols have been exploited via signature replay?

A: 0x Protocol (2017), Uniswap V2 permit functions, Curve Finance (cross-chain), and multiple bridges (2021-2023) suffered signature replay attacks. Aggregate losses exceed $100M+ from bridge replay exploits alone.


Q: How does Firepan detect signature replay?

A: Firepan enumerates signature verifications, analyzes message content, verifies nonce tracking, confirms chainId inclusion, constructs replay scenarios, and assesses cross-chain replay risks.


Q: Can signature replay be exploited after deployment?

A: Yes, signature replay is immediately exploitable post-deployment. Attackers observe valid signatures in mempool, logs, or events, then replay them indefinitely without new signing.


Q: How do I prevent signature replay?

A: Include nonce in signed message and increment after each use. Include block.chainid to prevent cross-chain replay. Include contract address to prevent collisions. Use EIP-712 for structured signing. Implement signature expiration via deadline parameter.

Conclusion

Signature replay enables indefinite reuse of valid cryptographic signatures, draining $100M+ across DeFi. The fix is straightforward: include nonce, chainId, and contract address in every signed message. EIP-712 (permit) and EIP-2612 implement this standard. Firepan's HOUND AI detects missing replay protections across all monitored contracts.

Start securing your smart contracts at https://app.firepan.com/

Firepan

Scan Your Contracts Now

12,453 contracts secured. 2,851 vulnerabilities blocked. 236 exploits prevented. Run a free surface scan — results in minutes, no credit card required.

Run Free Scan →