How to Analyze Smart Contracts for Replayable Approval Vulnerabilities

How to Analyze Smart Contracts for Replayable Approval Vulnerabilities

One of the sneakiest exploits in the DeFi ecosystem involves replayable approvals, where an attacker leverages a previously authorized approval path to steal tokens without the user’s fresh consent.

This post walks through what these vulnerabilities are, how to spot them in smart contracts, and what makes them dangerous.

What Is a Replayable Approval?

In ERC20 tokens, users commonly call approve(spender, amount) to allow another contract to transfer tokens on their behalf using transferFrom().

The danger begins when:

  1. A contract is approved once, even by a trusted user.

  2. The logic inside the approved contract can be changed or reconfigured (e.g., via a proxy or router).

  3. A malicious version of that contract or a nested call can reuse the original approval to steal tokens without a new signature or action from the user.

Where Do These Vulnerabilities Hide?

  1. Contracts That Hold swap() or Callback Logic

    • Especially if they’re set via a setRouter() function, check for modifiable addresses passed to critical logic.

  2. transferFrom() Without Validation

    • Watch for direct calls to token.transferFrom() from external addresses without robust auth.

  3. Routers and Zappers

    • Many Zapper-style contracts accept a user’s token and perform complex internal swaps.

    • If a developer can change the router to something malicious, approvals can be abused.

Red Flags in Code

  • IERC20(token).approve(address(router), ...) in setup functions

  • Router contracts that expose swap() logic that can be called externally

  • transferFrom() calls where the source is the contract itself, not the original user

  • Upgradeable contracts where router logic or destinations can be changed post-deployment

Checklist to Analyze Replayable Approval Risk

  • Does the contract allow dynamic router or handler changes?

  • Is there any way for a malicious contract to trigger approve() via a callback?

  • Can previously approved tokens be drained from the original approval?

  • Is there any authentication missing between the approval and token drain?

Takeaway

Replayable approval bugs often fly under the radar because they don’t involve permissionless exploits in the traditional sense, they rely on users having previously approved a contract that later becomes malicious.

Always ask: “Who controls the flow of approvals, and can they change it later?”