example-fork-detection
TEMPLATE — replace with the description of your rule. Should activate on the specific code patterns your fork has. Activate on `<your trigger keywords or…
Detect signature-replay, EIP-712 / EIP-2612 mistakes, malleable signatures, cross-chain replay, missing nonces. Activate on `ecrecover`, `permit`, meta-transactions, signed orders, signed approvals, EIP-712 domain construction, gasless transaction relayers.
$ npx -y skills add omermaksutii/RugProof --skill signature-replay --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/signature-replayContext preview
The summary Claude sees to decide when to auto-load this skill.
Detect signature-replay, EIP-712 / EIP-2612 mistakes, malleable signatures, cross-chain replay, missing nonces. Activate on `ecrecover`, `permit`, meta-transactions, signed orders, signed approvals, EIP-712 domain construction, gasless transaction relayers.
name: signature-replay description: Detect signature-replay, EIP-712 / EIP-2612 mistakes, malleable signatures, cross-chain replay, missing nonces. Activate on `ecrecover`, `permit`, meta-transactions, signed orders, signed approvals, EIP-712 domain construction, gasless transaction relayers.
bytes32 digest = keccak256(abi.encode(sender, amount)); // ← no nonce, infinitely replayable require(ecrecover(digest, v, r, s) == sender);
EIP-712 domain MUST include `chainId`. Without it, signing on Ethereum replays on Optimism/Arbitrum/etc.
bytes32 domain = keccak256(abi.encode(EIP712_DOMAIN, name, version, /* no chainId */ , verifyingContract));
DOMAIN_SEPARATOR = _hashDomain(block.chainid); // ← cached in constructor, breaks after fork
Re-compute when `block.chainid` differs.
ECDSA accepts both `(r, s)` and `(r, n-s)` for valid signatures. If you use the digest as a uniqueness key, attacker can flip s and replay. Enforce `s ≤ secp256k1n/2` and `v ∈ {27, 28}`. Or use OpenZeppelin's `ECDSA.tryRecover` which already does this.
address signer = ecrecover(digest, v, r, s); // returns 0 on bad sig require(roles[signer]); // ← if roles[address(0)] is ever true (default mapping behavior), it bypasses
Always `require(signer != address(0))` after ecrecover, or use OZ ECDSA.
Missing `address(this)` / `verifyingContract` in the signed payload. Same admin sig usable on multiple deployments.
See [[mev-frontrunning]] §permit.
Off-chain signed orders where the maker can replay across fills if the order doesn't include `salt` + `nonce` + cancellation mechanism.
Mixing Permit2's `SignatureTransfer` (one-shot) vs `AllowanceTransfer` (persistent). Read the contract's docs carefully.
| Pattern | Severity | |---|---| | Missing nonce in signed payload | **Critical** | | Missing chainId — cross-chain replay possible | **Critical** | | `ecrecover` without `signer != address(0)` check | **High** | | Malleable signature accepted (no s-bound check) | **High** | | Cached DOMAIN_SEPARATOR without fork-aware re-compute | **High** | | Signed payload omits `verifyingContract` | **High** | | Order salt missing, no cancellation mechanism | **High** | | Off-by-one chainId for L2 chains (e.g. Polygon = 137 not 1) | **High** | | Permit gas-grief on revert reverts in batch | **Medium** |
Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy
Repo: omermaksutii/RugProof
TEMPLATE — replace with the description of your rule. Should activate on the specific code patterns your fork has. Activate on `<your trigger keywords or…
Detect unsafe assumptions about Solady's gas-optimized ERC20/ERC2612 permit and DN404 metadata. Solady's ERC20 uses custom storage slots, returns bools via…
Detect front-runnable ownership initialization in Solady Ownable / OwnableRoles. Solady's `_initializeOwner` is a guarded one-time setter (it reverts with…
Detect Solady SafeTransferLib calls that assume the token has code. SafeTransferLib.safeTransfer/safeTransferFrom/safeApprove deliberately skip the EXTCODESIZE…
Detect Uniswap V4 hooks that fail to settle currency deltas with the PoolManager. Every credit/debit a hook creates (BeforeSwapDelta, afterSwap hookDelta,…
Detect Uniswap V4 hooks whose address-encoded permission flags don't match the callbacks the hook actually implements. In V4 the hook's permissions live in the…