name: vuln-web3-token description: "Scan for token standard flaws (ERC-20/721/1155), signature replay/malleability, permit issues. Appends to vulnerabilities.md." allowed-tools: Read Bash(find *) Bash(grep *) Bash(head *) Bash(wc *) Bash(cat *) Bash(ls *) Write argument-hint: <path to threat-model.md, defaults to ./assessment/threat-model.md>
Bug Bounty — Step 3n: Token & Signature Vulnerabilities
Scan for ERC-20/721/1155 token implementation flaws and cryptographic signature misuse.
Input
$ARGUMENTS
- Read
./assessment/threat-model.md(or provided path) for priority targets - Read
./assessment/recon.mdfor entry points and data flows - If either is missing, tell the user which step to run first
Vulnerability Patterns
ERC-20 Approval Race Condition
approve()withoutincreaseAllowance/decreaseAllowance- Front-runnable approval change (old allowance spent before new one set)
- Missing zero-approval-first pattern
Grep patterns: approve(, allowance(, increaseAllowance, decreaseAllowance, _approve(
Non-Standard Token Behavior
- Fee-on-transfer tokens (received amount < sent amount)
- Rebasing tokens (balance changes without transfer)
- Tokens with blacklist/pause (transfer can revert unexpectedly)
- Tokens returning
falseinstead of reverting on failure - Tokens with >18 or <18 decimals breaking assumptions
Grep patterns: balanceOf(, transfer(, transferFrom(, decimals(), fee, tax, rebase, blacklist, pause
Infinite Mint
- Unprotected
mint()function - Mint amount not validated against cap
- Overflow in mint calculation allowing excessive minting
- Bridge/wrapper mint without proper burn verification
Grep patterns: mint(, _mint(, totalSupply, maxSupply, cap(, MAX_SUPPLY
Token Accounting Errors
- Balance tracking diverging from actual token balance
- Missing balance update on direct token transfer (donation attack)
balanceOf(address(this))used instead of internal accounting- Transfer hooks (
_beforeTokenTransfer) modifying expected behavior
Grep patterns: balanceOf(address(this)), _balances[, _beforeTokenTransfer, _afterTokenTransfer, ERC777, tokensReceived
Signature Replay
- Missing nonce in signed messages (same signature valid multiple times)
- Missing
chainIdin EIP-712 domain separator (cross-chain replay) - Nonce not incremented on successful use
- Signature valid across multiple contracts (missing
address(this)in hash)
Grep patterns: ecrecover, ECDSA.recover, nonce, nonces[, _useNonce, DOMAIN_SEPARATOR, domainSeparator, EIP712
Signature Malleability
ecrecoverwithout checkingsvalue is in lower half- Both
(v, r, s)and(v', r, s')accepted for same message - Missing
vvalue validation (only 27 or 28) - Using raw
ecrecoverinstead of OpenZeppelin ECDSA library
Grep patterns: ecrecover(, ECDSA, v, r, s, 0x7FFFFFFF, bytes32 s
ecrecover Zero Address
ecrecoverreturnsaddress(0)on invalid signature- Missing
require(recovered != address(0))check - Zero address has special meaning in some protocols (burn address with balance)
Grep patterns: ecrecover(, require(signer != address(0), address(0), recover(
Permit (EIP-2612) Flaws
- Permit deadline not enforced
- Permit nonce not properly tracked per-user
- Permit signature usable after token transfer (follows token, not user)
- Missing permit support detection (griefing on
permit()revert)
Grep patterns: permit(, PERMIT_TYPEHASH, nonces, deadline, EIP2612, IERC20Permit
Permit2 / Signature-Based Approvals (2024-2026 Standard)
- Permit2
SignatureTransferreplay (nonce not invalidated after use) - Permit2
AllowanceTransferwith excessive expiration (permanent approval) - Witness data manipulation in Permit2 (extra data not validated by protocol)
- Missing Permit2
InvalidateNonceson order cancellation - Unordered nonces allowing selective replay of specific permits
- Token approvals via Permit2 surviving contract upgrades
- Permit2 batch transfer with mixed token amounts (partial fill exploitation)
Grep patterns: ISignatureTransfer, IAllowanceTransfer, Permit2, permit2, PermitTransferFrom, PermitBatchTransferFrom, SignatureTransferDetails, witness, permitWitnessTransferFrom, invalidateUnorderedNonces, nonceBitmap, PERMIT2
ERC-777 / Hooks Abuse
tokensReceivedhook enabling reentrancytokensToSendhook blocking transfers (DoS)- ERC-777 backward compatibility issues with ERC-20 assumptions
- Missing ERC-1820 registry check
Grep patterns: ERC777, tokensReceived, tokensToSend, IERC777Recipient, IERC777Sender, ERC1820, _callTokensReceived
Process
- Identify token standards — ERC-20, ERC-721, ERC-1155, ERC-777, ERC-4626
- Check approval patterns — is approve race condition mitigated?
- Test with non-standard tokens — does the protocol handle fee-on-transfer, rebasing, or non-reverting tokens?
- Audit mint/burn — are they properly access-controlled and bounded?
- Check all signature usage — nonce, chainId, contract address, malleability, zero-address
- Verify permit implementation — deadline, nonce tracking, domain separator
- Assess impact — token theft, infinite mint, signature replay for unauthorized actions
Output
Append to ./assessment/vulnerabilities.md:
# Vulnerability Findings — Token & Signature
**Date**: {date}
**Scanner**: vuln-web3-token
## Findings
### VULN-TOKEN-001: {Title}
**Severity**: {Critical/High/Medium/Low}
**Confidence**: {High/Medium/Low}
**Category**: {Approval Race / Non-Standard Token / Infinite Mint / Accounting / Signature Replay / Malleability / Permit / ERC-777}
**Location**: `{file}:{line}`
**CWE**: CWE-{362|345|347|284}
**Description**:
{What the vulnerability is}
**Vulnerable Code**:
```solidity
{code snippet}
`` `
**Attack Scenario**:
1. {Step-by-step exploitation}
**Proof of Concept**:
```solidity
{Exploit showing token theft or signature replay}
`` `
**Impact**:
{Token theft, unauthorized approval, infinite mint, replay attack}
**Remediation**:
```solidity
{Fixed code}
`` `
---
Positive Observations
While scanning, note any strong security patterns relevant to this scanner's domain. Add them to the # Positive Security Observations section at the end of vulnerabilities.md:
- {scanner-name}: {what the codebase does well in this area}
Rules
- For non-standard tokens, identify which specific token causes the issue — not all tokens are fee-on-transfer.
- For signatures, show the exact replay scenario — same chain, cross-chain, or cross-contract.
- Check OpenZeppelin usage — OZ ECDSA library handles malleability and zero-address checks.
- Idempotent output — if
vulnerabilities.mdalready has a# Vulnerability Findings — Token & Signaturesection, replace it entirely. Seesc3-vuln-scanidempotency rule. - Save to
./assessment/vulnerabilities.mdand confirm.