signature-malleability

Solid

Detect ECDSA signature malleability and ecrecover pitfalls — missing low-s (EIP-2) enforcement, unconstrained v, unchecked address(0) from ecrecover, replay across chainId/contract from a missing EIP-712 domain separator, EIP-2098 compact-signature confusion, and signature reuse. Activate whenever code calls ecrecover directly, parses (r,s,v) from bytes, or verifies signed messages without OpenZeppelin ECDSA.

AI & Automation 38 stars 5 forks Updated 2 days ago MIT

Install

View on GitHub

Quality Score: 82/100

Stars 20%
53
Recency 20%
100
Frontmatter 20%
70
Documentation 15%
100
Issue Health 10%
50
License 10%
100
Description 5%
100

Skill Content

# Signature malleability detection ## When this applies Trigger on any of: - Direct `ecrecover(hash, v, r, s)` calls (not via OpenZeppelin `ECDSA.recover`) - Manual `(r, s, v)` decoding from a `bytes` signature with assembly - Permit / meta-tx / order-book / claim flows that verify a signed digest - Signatures used as nonces or dedup keys (e.g. `usedSig[sig] = true`) - EIP-712 typed-data verification, or its absence where one is needed ## Detection patterns ### Missing low-s enforcement / malleable sig (HIGH if sig is a key) ```solidity address signer = ecrecover(hash, v, r, s); // no s-range check require(signer == expected); usedSignature[keccak256(abi.encode(r,s,v))] = true; // ← dedup keyed on sig bytes ``` **Signal:** for any valid `(r,s,v)` the "flipped" signature `(r, n - s, v ^ 1)` recovers the *same* signer (the classic Bitcoin/Ethereum transaction-malleability class). If the signature itself is the replay key, an attacker submits the twin and bypasses dedup. Enforce `s <= secp256k1n/2` (EIP-2). ### Unchecked ecrecover returning address(0) (HIGH) ```solidity address signer = ecrecover(hash, v, r, s); require(signer == owner); // if owner could ever be address(0)... or no check at all ``` **Signal:** malformed inputs make `ecrecover` return `address(0)`. Any code path where the compared-against value can be `address(0)` (uninitialized mapping slot, default) authenticates an attacker with garbage. Always `require(signer != address(0))`. ### Unconstrained v (...

Details

Author
iktok90-design
Repository
iktok90-design/ai-smart-contract-auditor
Created
1 weeks ago
Last Updated
2 days ago
Language
JavaScript
License
MIT

Bundled in these plugins

Similar Skills

Semantically similar based on skill content — not just same category