Permit Frontrunning
Detects ERC-2612 permit implementations where nonce mismanagement enables frontrunning attacks on gasless approvals.
Permit Frontrunning
Overview
The permit frontrunning detector identifies contracts that use ERC-2612 permit() followed by transferFrom() in a way that is vulnerable to frontrunning. An attacker who observes a pending permit + transferFrom transaction can frontrun it by submitting just the permit call, causing the original transaction to revert (nonce already used) while the attacker’s subsequent transferFrom succeeds using the now-active approval.
Sigvex identifies sequences where permit() is called and its success is required before transferFrom(), without handling the case where the permit may have already been executed.
Why This Is an Issue
ERC-2612 permits enable gasless token approvals via off-chain signatures. The frontrunning attack works because permit() is idempotent at the signature level but not at the nonce level. If an attacker submits the permit before the intended caller, the nonce increments, and the caller’s transaction reverts. Contracts that wrap permit + transferFrom in a single function are particularly vulnerable.
How to Resolve
// Before: Vulnerable — reverts if permit was already used
function depositWithPermit(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
token.permit(msg.sender, address(this), amount, deadline, v, r, s); // Reverts if frontrun
token.transferFrom(msg.sender, address(this), amount);
}
// After: Fixed — catch permit failure (approval may already exist)
function depositWithPermit(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
try token.permit(msg.sender, address(this), amount, deadline, v, r, s) {} catch {}
token.transferFrom(msg.sender, address(this), amount); // Works if already approved
}
Detection Methodology
- Permit call identification: Locates calls matching the
permit(address,address,uint256,uint256,uint8,bytes32,bytes32)selector. - Return check analysis: Checks whether the permit call’s return value gates subsequent operations via
requireorrevert. - TransferFrom sequence: Identifies
transferFromcalls followingpermiton the same token. - Error handling check: Determines whether the permit call is wrapped in try/catch or otherwise handles revert gracefully.
Limitations
False positives: Contracts where the permit-then-transfer is only callable by a trusted relayer may be flagged. False negatives: Non-standard permit implementations with different selectors may be missed.
Related Detectors
- Front-Running — detects general frontrunning vulnerabilities
- Signature Replay — detects signature reuse attacks