ERC-20 Approve Race
Detects ERC-20 approve functions vulnerable to the front-running race condition where a spender can spend both old and new allowances.
ERC-20 Approve Race
Overview
The ERC-20 approve race detector identifies token contracts where the approve() function sets a new allowance without requiring the current allowance to be zero first. This creates a front-running window: when a token holder changes an allowance from N to M, the spender can observe the pending transaction, quickly spend N tokens, and then spend M more tokens after the new allowance takes effect — spending N+M instead of the intended M.
Why This Is an Issue
The approve-then-transferFrom pattern is fundamental to DeFi interactions. Users regularly adjust allowances for routers, vaults, and aggregators. If the spender (or a MEV searcher acting on the spender’s behalf) can front-run the allowance change, they extract the full old allowance plus the new one. While the ERC-20 standard acknowledges this issue, many implementations do not mitigate it.
How to Resolve
// Before: Vulnerable — direct allowance overwrite
function approve(address spender, uint256 amount) external returns (bool) {
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
// After: Fixed — require zero-first or use increaseAllowance
function approve(address spender, uint256 amount) external returns (bool) {
require(
amount == 0 || _allowances[msg.sender][spender] == 0,
"Approve: reset first"
);
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function increaseAllowance(address spender, uint256 added) external returns (bool) {
_allowances[msg.sender][spender] += added;
emit Approval(msg.sender, spender, _allowances[msg.sender][spender]);
return true;
}
Detection Methodology
- Approve function identification: Locates functions matching the ERC-20
approve(address,uint256)selector (0x095ea7b3). - Allowance write pattern: Checks if the function performs a direct SSTORE to the allowance mapping without reading the current value first.
- Zero-check absence: Flags implementations that do not require the current allowance to be zero before setting a non-zero value.
- SafeApprove detection: Checks for
increaseAllowance/decreaseAllowancepatterns that mitigate the issue.
Limitations
False positives: Some protocols intentionally allow direct allowance overwrites because their threat model does not include front-running (e.g., the spender is a trusted protocol contract). False negatives: Custom allowance mechanisms that do not use standard storage patterns may not be detected.
Related Detectors
- Front-Running — detects general front-running vulnerabilities
- MEV Vulnerabilities — detects MEV extraction patterns