Permit Vulnerabilities Remediation
Overview
Related Detector: Permit Vulnerabilities
ERC-2612 permit enables gasless approvals from an off-chain signature, but a naive integration can be griefed by a front-run permit, desynchronized by out-of-order nonces, or replayed if the deadline is loose. This guide covers the integration as a whole; see also Permit Frontrunning and Missing Deadline for the individual issues.
Recommended Fix
Before (Vulnerable)
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 front-run
token.transferFrom(msg.sender, address(this), amount);
}
After (Fixed — tolerate a consumed permit, enforce a real deadline)
function depositWithPermit(uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, "Permit expired"); // enforce, don't accept max
// If the permit was already applied (front-run/replayed), proceed on the allowance.
if (token.allowance(msg.sender, address(this)) < amount) {
try token.permit(msg.sender, address(this), amount, deadline, v, r, s) {} catch {}
}
require(token.allowance(msg.sender, address(this)) >= amount, "Permit failed");
token.transferFrom(msg.sender, address(this), amount);
}
Use short deadlines, rely on the token’s own nonce for replay protection, and never treat a reverting permit as a hard failure when the allowance is already sufficient.
Common Mistakes
- Letting a front-runner’s
permitsubmission revert and fail the whole operation (see permit-frontrunning). - Passing
type(uint256).maxas the deadline, removing the replay window bound. - Assuming every token implements ERC-2612; some use Permit2 or no permit at all — branch accordingly.