DeFi Intel

EIP-2612 Permit Exploits: Nonce Vulnerabilities in Off-Chain Approvals

Quick answerEIP-2612 permits allow gasless token approvals via off-chain signatures. Their primary vulnerability is nonce reuse enabling replay attacks, compounded by signature malleability and cross-chain replays. Mitigation requires strict nonce incrementation, domain separators with chain ID, and ECDSA signature validation with `s` constrained to lower half.

EIP-2612 permit exploits have emerged as a critical concern in DeFi security, targeting the elegant but fragile mechanism of off-chain token approvals. At its core, EIP-2612 (also known as ERC-20 permit) allows users to approve token transfers using a signed EIP-712 typed message, eliminating the need for a separate on-chain approval transaction. However, this convenience introduces a new attack surface centered on nonce vulnerabilities—specifically nonce reuse, signature malleability, and cross-chain replay attacks—that can drain user funds if not mitigated.

This guide dissects the mechanics of these exploits, drawing from real-world implementations in protocols like Uniswap V2 and OpenZeppelin’s popular libraries. We cover how permits work, where nonces fit in, the exact attack vectors, and concrete defensive measures. By the end, you’ll understand why EIP-2612 require rigorous nonce management and domain separation to remain safe in a multi-chain, frontrunning-prone environment.

Key takeaways
  • Nonces are the primary defense against replay attacks but must be strictly incremented per user and tied to a specific chain via domain separator.
  • Signature malleability can be mitigated by constraining `s` to the lower half of the secp256k1 curve and rejecting `v` values not 27 or 28.
  • Domain separators must include chain ID and verifying contract address to prevent cross-chain replays; avoid hardcoding.
  • Frontrunning permit execution can be mitigated using commit-reveal schemes or private mempool relays (e.g., Flashbots).
  • OpenZeppelin’s `ERC20Permit` and `ECDSA` libraries implement most mitigations correctly, but integrators must use the latest versions and understand the underlying nonce logic.
  • Audits and formal verification are essential for any contract handling off-chain signatures; nonce invariants should be explicitly checked.

What Are EIP-2612 Permits and Why Do They Introduce Exploit Surface?

EIP-2612 extends the ERC-20 standard with a permit function that accepts an off-chain signature authorizing a token spend. Instead of calling approve on-chain (which costs gas and requires ETH), a user signs a structured message off-chain and submits it along with the actual transfer transaction, saving one transaction for the user and enabling meta-transactions. The signature includes a nonce (a unique, monotonically increasing counter) per user-address pair, intended to prevent replay of the same permit signature. However, flaws in nonce management—or missing domain separators—open the door to exploits.

The core exploit surface arises because the permit function must validate the signature, update the nonce, and then call _approve atomically. If any of these steps can be replayed (same nonce reused) or if the signature can be rearranged across chains or frontrun in the mempool, an attacker can drain approvals. The exact vulnerabilities fall into three categories: nonce reuse (replay attacks within the same chain), signature malleability (forged valid signatures from a legitimate one), and cross-chain replay (domain separator missing chain ID). Understanding each is essential for builders.

How Does the Nonce Mechanism Work in Permit Signatures?

In a typical EIP-2612 implementation (e.g., OpenZeppelin’s ERC20Permit), each user maintains a mapping nonces[owner] that increments by one after every successful use of a permit. The signature’s permit message includes the current nonce value, the spender, the amount, the deadline, and the domain separator (which encodes the chain ID and verifying contract). The solidity code checks require(nonces[owner] == nonce, "Permit: invalid nonce"); and then increments nonces[owner]++.

If the nonce is not checked or is derived from user-controlled data (e.g., hash(nonce) without state tracking), an attacker can replay the same signature multiple times. The nonce must be part of the signed message and must be validated against storage. A common pitfall is using nonce[owner][spender] (nonce per spender) which complicates replay protection across different spenders—instead, a single per-user nonce is standard and safe when combined with the spender address inside the message.

The Core Vulnerability: Nonce Reuse and Replay Attacks

The simplest EIP-2612 permit exploit occurs when the nonce is not updated atomically with the signature verification. If a contract accepts a permit signature but fails to increment the nonce immediately, the attacker can copy the signed message and call permit again. This is effectively a replay attack. In practice, most implementations do increment the nonce, but flaws arise in edge cases: using a nonce derived from block.number (which can be reused if mined in the same block), or using a nonce that is based on the signature itself (malleable).

Consider a hypothetical contract that uses a global nonce for all users (bad practice). A malicious user signs a permit, then before the first permit transaction is mined, they extract the signature and spam it themselves—they can drain their own approval multiple times. This is a real risk in poorly designed token bridges or custom permit implementations. Mitigation: always use a per-address, monotonically increasing nonce stored in contract state, incremented before executing any side effects.

Signature Malleability: Exploiting the `v` Value and `s` Range

ECDSA signatures, used by EIP-712 and EIP-2612, are malleable: the s value can be changed to curve_order - s and v can be flipped (27 <-> 28), producing a different 65-byte signature that still recovers to the same public key. If the contract does not validate that s is in the lower half of the secp256k1 curve (i.e., s <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0), an attacker can take an existing permit signature, malleate it, and submit it as a new valid signature—with a different hash but the same underlying approval.

This enables a replay attack even if the nonce is correctly validated: the attacker can malleate the signature and reuse it with the same nonce, because the hash changed and the contract may not check the nonce against the hash. Most modern libraries (OpenZeppelin v4.9+) include an _useNonce that recovers the signer from the digest and checks nonce, but if the signature is malleated, the recovered address is identical, and the nonce check passes. The fix is to verify require(s <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid signature s"); inside the custom permit function or use OpenZeppelin’s ECDSA.tryRecover which does this automatically.

Cross-Chain Replay Attacks: A Silent Drain Vector

A particularly insidious EIP-2612 permit exploit occurs across multiple EVM chains. If the domain separator (the EIP712Domain struct) does not include the chain ID, a signature signed on Ethereum mainnet can be replayed on Polygon, BSC, or any other EVM chain that uses the same contract address (or a mirrored deployment). The attacker simply copies the signed message, broadcasts it on another chain, and the contract there—which also tracks nonces independently—accepts it as a fresh permit. The user’s approved amount is drained on that secondary chain.

This is not theoretical: several early permit-enabled tokens computed their EIP712Domain separator once at deployment with the chain ID fixed as a constant. After a chain split (hard fork), the cached separator no longer reflected the new chain's ID, so a signature could remain valid on both the original and forked chains. Many bridges and multi-chain tokens still ship with insufficient domain separators. Correct mitigation: the domain separator must encode the chain ID (e.g., block.chainid) and the contract address uniquely. OpenZeppelin’s ERC20Permit does this via _domainSeparatorV4().

Frontrunning Permit Execution: The Sandwich Attack Variant

Even with perfect nonce and signature validation, permit-based approvals can be frontrun. An attacker monitors the mempool for a transaction that includes a permit followed by a transferFrom (often in the same meta-transaction). The attacker can extract the signature from the pending transaction and craft a new transaction that calls permit with the same signature (if nonce not yet consumed) before the original transaction, effectively stealing the approval and then draining the tokens before the user’s intended transfer executes.

This is a variant of a sandwich attack. It requires that the original transaction exposes the signature in the calldata (which meta-transactions do). To mitigate, protocols should use a commit-reveal scheme: the user first broadcasts a hash of the signature, then reveals it later. Alternatively, combine permit with a flashbots-style private relay. Sadly, most DeFi protocols today remain exposed; users can protect themselves by using EIP-2612 permits only with wallets that support private mempool submission (e.g., via eth_sendBundle).

Real-World Exploits and Near-Misses

Several high-profile incidents illustrate these vulnerabilities:

These cases underscore that even well-audited protocols can miss the subtleties. Using standard audited libraries (OpenZeppelin, Solmate) is strongly recommended, but integrators must still ensure they use the latest version and understand the nonce trade-offs.

Comparison Table: Traditional approve vs. EIP-2612 permit – Security Trade-offs

FeatureTraditional approve (on-chain)EIP-2612 permit (off-chain)
Gas cost to userHigher (two transactions)Lower (one combined tx)
Frontrunning riskLow (atomic approve + swap)Higher (signature exposed in mempool)
Replay protectionInherent (state-based)Requires careful nonce management
Cross-chain safetyInherent (state per chain)Requires chain ID in domain separator
Signature malleabilityNot applicableMust validate s ≤ curve order /2
Nonce management complexityNoneMonotonic nonce per address; avoid nonce reuse
User experienceTwo transactions, need ETHOne transaction, gasless possible

Mitigation Strategies: Nonce Incrementation, Domain Separators, and Signature Validation

To secure EIP-2612 permit implementations, follow these best practices:

Future Directions: ERC-4494, EIP-712, and Post-Quantum Considerations

EIP-2612’s permit pattern has been complemented by related standards such as ERC-4494 (permit for ERC-721) and by Uniswap’s Permit2, which layers nonce management, expiries, and a shared allowance system on top of existing token approvals. Modern libraries also standardize protections against signature malleability by constraining the ECDSA s value to the lower half of the curve and rejecting non-canonical v values.

Looking further, the rise of post-quantum cryptography will fundamentally change signature schemes. EIP-2612 exploits are irrelevant once ECDSA is replaced by lattice-based schemes (e.g., Falcon, Dilithium), but the nonce concept remains: any signature scheme needs replay protection. DeFi builders should design contracts with upgradeable signature verification to adapt to future standards. Meanwhile, understanding EIP-2612’s nonce vulnerabilities is crucial for anyone handling off-chain approvals today—the lessons apply to any future standard.

Common mistakes to avoid

Frequently asked questions

Can a permit be reused if the nonce is not incremented?

Yes, if the contract does not increment the nonce after verifying the signature, an attacker can collect the signed message and call `permit` multiple times, draining the approved amount until the allowance runs out.

How do I protect against cross-chain replay attacks in EIP-2612?

Include the chain ID (`block.chainid`) and the verifying contract address in the EIP-712 domain separator used in the permit message. This ensures that a signature generated for one chain is invalid on any other chain.

What is signature malleability in EIP-2612?

ECDSA signatures are mathematically malleable: an attacker can derive a different byte representation of a valid signature that still recovers the same address. If the contract does not restrict `s` to the lower half of the curve, this malleated signature can be used to replay a permit with the same nonce.

Is EIP-2612 safe to use with hardware wallets?

Hardware wallets (Ledger, Trezor) support signing EIP-712 messages, so EIP-2612 is safe from the signing perspective. However, the frontrunning risk remains: the signature is exposed in the transaction calldata. Hardware wallet users should use wallets that provide private mempool submission or avoid high-value permit approvals.

Track the entities behind the concepts

DeFi Intel maps 11,000+ protocols, tokens and companies to a typed knowledge graph — with live data, incidents and regulation.

Entities mentioned