Skip to content
Back to skills

2592 Missing Protection Signature Replay 88f560d0

ASecurity

- Contract verifies ECDSA signatures for authorization - The signed message does not include a nonce, OR does not include the contract address, OR does not include the chain ID - No mechanism tracks which signatures have been processed

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
business

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2592-missing-protection-signature-replay_88f560d0 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2592 Missing Protection Signature Replay 88f560d0?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2592 Missing Protection Signature Replay 88f560d0
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2592-missing-protection-signature-replay-88f560d0/badge)](https://www.skillsdirectory.com/skills/tools-only-2592-missing-protection-signature-replay-88f560d0)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Missing Protection Against Signature Replay

## Preconditions
- Contract verifies ECDSA signatures for authorization
- The signed message does not include a nonce, OR does not include the contract address, OR does not include the chain ID
- No mechanism tracks which signatures have been processed

## Vulnerable Pattern
```solidity
function executeWithSig(address to, uint256 amount, bytes memory sig) external {
    // Missing: nonce, contract address, and chain ID in hash
    // Same signature can be replayed on same contract, other contracts, or other chains
    bytes32 hash = keccak256(abi.encodePacked(to, amount));
    address signer = ECDSA.recover(hash, sig);
    require(signer == authorizer, "invalid sig");

    // No nonce tracking — same signature can be submitted repeatedly
    _transfer(to, amount);
}
```

## Detection Heuristics
1. Search for `ecrecover` or `ECDSA.recover` usage
2. Examine what is included in the signed hash — check for:
   - Nonce: is there a per-signer incrementing nonce? Flag if absent (enables same-contract replay)
   - Contract address (`address(this)`): flag if absent (enables cross-contract replay)
   - Chain ID (`block.chainid`): flag if absent (enables cross-chain replay)
3. Check if processed signatures/hashes are tracked in a mapping to prevent reuse
4. Check if EIP-712 domain separator is used (it includes contract address and chain ID automatically)
5. Verify that the nonce is incremented BEFORE execution, not after (to prevent reentrancy-based replay)

## False Positives
- EIP-712 domain separator is used with proper nonce tracking (covers address + chainId + nonce)
- The signed message includes all three: nonce, contract address, and chain ID
- The signature authorizes a one-time action that is inherently non-replayable (e.g., EIP-2612 permit with deadline and nonce)

## Remediation
- Include nonce, `address(this)`, and `block.chainid` in the signed message hash
- Track processed nonces per signer in a mapping
- Use EIP-712 structured data signing with a domain separator
```solidity
mapping(address => uint256) public nonces;

function executeWithSig(address to, uint256 amount, bytes memory sig) external {
    uint256 nonce = nonces[msg.sender]++;
    bytes32 hash = keccak256(abi.encodePacked(
        to, amount, nonce, address(this), block.chainid
    ));
    bytes32 ethHash = ECDSA.toEthSignedMessageHash(hash);
    address signer = ECDSA.recover(ethHash, sig);
    require(signer == authorizer, "invalid sig");
    _transfer(to, amount);
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.