DEFI RISK AND SMART CONTRACT SECURITY

Understanding the Risks of ERC20 Approval and transferFrom in DeFi

8 min read
#DeFi #Ethereum #Smart Contract #ERC20 #Approval
Understanding the Risks of ERC20 Approval and transferFrom in DeFi

Understanding the Risks of ERC20 Approval and transferFrom in DeFi

The ERC20 token standard is the backbone of most token interactions on Ethereum. It defines a set of functions that allow tokens to be transferred, approved, and queried. Two of the most frequently used functions in DeFi protocols are approve and transferFrom. Together they enable smart contracts to move tokens on behalf of users without requiring the user to send a transaction each time. While this convenience powers many of the automated processes that make decentralized finance possible, it also introduces a range of security risks that developers and users must understand. Learn more about these vulnerabilities in our in‑depth guide, A Deep Dive Into ERC20 Approval Vulnerabilities for Developers.

How ERC20 Approval Works

In a typical token transfer, the sender calls the transfer function of a token contract, specifying the recipient and the amount. In contrast, approve allows a token holder to authorize another address—often a smart contract—to spend a specific amount of their tokens. The syntax is straightforward:

function approve(address spender, uint256 amount) external returns (bool)

The spender can then call transferFrom to move tokens from the holder’s balance to any destination address, as long as the amount does not exceed the allowance set by approve. The allowance is stored in a mapping:

mapping(address => mapping(address => uint256)) public allowance;

When transferFrom is executed, the contract deducts the spent amount from the allowance and updates balances accordingly.

The Dual Nature of transferFrom

The transferFrom function is essential for many DeFi use cases: liquidity provision, yield farming, decentralized exchanges, and more. It allows a contract to move tokens on behalf of a user without requiring an additional transaction from that user. This reduces gas costs and simplifies interactions. However, because the contract has the power to move tokens, it can also become an attack vector if the approval and transfer logic is not carefully designed.

Core Vulnerabilities

Infinite Allowance and the “Approve All” Problem

This issue is detailed in Beyond the Basics: ERC20 Approval Pitfalls for Smart Contracts. A common pattern is to set an unlimited allowance (uint256(-1) or type(uint256).max) so that a contract can spend any amount without re‑approving each time. While convenient, this exposes the user’s entire balance to the spender. If the spender contract is compromised or malicious, the attacker can drain the user’s funds at any time.

Race Conditions and Allowance Manipulation

ERC20 does not enforce a check–modify–set sequence when changing allowances. A typical race condition unfolds as follows:

  1. User calls approve(spender, newAmount) while a pending transaction from a previous approve is still pending.
  2. The transaction with the smaller newAmount executes first, setting the allowance to a low value.
  3. The later transaction executes, increasing the allowance to the intended high value.
  4. In the interval between these two events, the spender can call transferFrom to move tokens up to the low allowance before the higher allowance becomes effective.

Because of this, users must explicitly set allowances to zero before changing them to a new value to avoid accidental or malicious over‑spending. For a deeper understanding of how these attacks unfold, see The Anatomy of transferFrom Attacks and How to Stop Them.

Front‑Running and Time‑Dependent Attacks

transferFrom relies on the state of balances and allowances at the moment of execution. An attacker can front‑run a legitimate transferFrom transaction by submitting a competing transaction that changes the allowance or balance in a way that benefits the attacker. This can happen in flash loan attacks, sandwich attacks on decentralized exchanges, or simply by abusing the lack of atomicity in state changes.

Reentrancy via transferFrom

Some contracts misuse transferFrom in callback functions, creating reentrancy vulnerabilities. If a contract calls transferFrom and then executes external code that can call back into the original contract before the state has fully updated, the attacker can potentially move more tokens than intended. Proper use of the checks‑effects‑interactions pattern and non‑reentrant modifiers mitigates this risk.

Unchecked Allowance Logic

Many contracts assume that an allowance of zero means “no permission” and any non‑zero allowance is “full permission.” However, the ERC20 standard does not guarantee that zero allowances cannot be used. A malicious contract can exploit this by setting an allowance to a large value, then reducing it to zero in a way that still allows the spender to use the remaining balance before the zero state is enforced.

Real‑World Examples

  • The DAO Attack (2016): Although not directly related to ERC20, the DAO hack highlighted the dangers of reentrancy in smart contracts. The same principles apply to contracts that use transferFrom in callbacks.
  • Sushiswap Liquidity Provider (2020): An attacker exploited a race condition in the liquidity provision contract that relied on approve/transferFrom. By manipulating allowances, the attacker drained liquidity pools.
  • Yearn Finance (2021): A misconfigured approve call in a vault contract allowed an attacker to withdraw tokens without proper authorization, demonstrating the risks of infinite allowances.

These incidents illustrate how seemingly innocuous functions can become the foundation for large‑scale exploits.

Mitigation Strategies for Developers

1. Prefer the safeApprove Pattern

OpenZeppelin’s SafeERC20 library provides safeApprove, which checks that the allowance is zero before setting a new value. This prevents accidental overwriting of an existing allowance. See our detailed guide for implementing safeApprove in practice: Secure Your ERC20 Tokens: Best Practices for Approval and transferFrom.

SafeERC20.safeApprove(token, spender, 0);
SafeERC20.safeApprove(token, spender, newAmount);

2. Use approveAndCall or permit When Available

Some tokens implement an approveAndCall function or the EIP‑2612 permit extension, which allows a user to sign an approval off‑chain and have the contract validate it on‑chain. This eliminates the need for an explicit approval transaction and reduces the window of vulnerability.

3. Implement Short‑Lived Allowances

Where possible, design contracts to use time‑bound approvals. By adding a deadline parameter to approve and checking it in transferFrom, you limit the window during which a spender can use the allowance.

function approve(address spender, uint256 amount, uint256 deadline) external returns (bool);

4. Avoid Infinite Allowances

If the contract needs to spend tokens frequently, consider resetting the allowance to zero before each transfer rather than granting an unlimited amount. This reduces the exposure if the contract is compromised.

5. Follow the Checks‑Effects‑Interactions Pattern

Always update state (checks and effects) before making external calls (interactions). This reduces the risk of reentrancy when transferFrom is used in a callback.

6. Conduct Formal Verification and Audits

For contracts that handle large amounts of tokens or are part of a DeFi protocol, formal verification can mathematically prove that certain properties hold (e.g., allowance cannot be exceeded). Auditors should specifically test edge cases involving approve/transferFrom.

7. Use Access Control Wisely

Restrict which addresses can call transferFrom or change allowances. The Ownable or AccessControl patterns help limit exposure.

8. Log and Monitor

Emit events on allowance changes and token transfers. External monitoring services can flag anomalous patterns, such as sudden large approvals or transfers.

Best Practices for Users

Keep Allowances Minimal

Only grant the maximum amount of tokens a contract truly needs. For example, if a DeFi protocol requires a 1000‑token allowance for a one‑time action, avoid setting it to an unlimited value.

Revoke Unused Approvals

Many wallets and interfaces now support revoking token approvals. Regularly audit your token approvals and remove those that are no longer needed.

Verify Contracts Before Approving

Before interacting with a contract, review its source code if available, or use a reputable platform that lists audited contracts. Avoid approving tokens to unknown or unverified addresses.

Use Gas‑Efficient Approvals

Some protocols allow token approvals via signed messages (permit). This eliminates the need for an on‑chain approval transaction, reducing gas costs and the attack surface.

Watch for Front‑Running

When sending large transferFrom transactions, consider using a private transaction pool or delaying execution to avoid being front‑ran by attackers.

Emerging Standards and Future Directions

The DeFi community has recognized the pitfalls of the traditional approve/transferFrom paradigm. Several proposals aim to provide safer alternatives:

  • ERC‑777 adds a send function with hooks that notify the recipient contract before the transfer, reducing race conditions.
  • ERC‑20 Permit (EIP‑2612) allows approvals via signatures, eliminating on‑chain approval transactions.
  • ERC‑4626 standardizes vaults, adding explicit deposit and withdrawal logic that reduces the need for arbitrary transferFrom calls.

Additionally, layer‑2 scaling solutions and optimistic rollups are implementing their own token standards with improved allowance management.

Conclusion

The approve and transferFrom functions are powerful tools that enable the composability of DeFi. Yet their simplicity masks a host of vulnerabilities—race conditions, infinite allowances, reentrancy, and front‑running—that can be exploited by attackers. Developers must adopt robust patterns such as safeApprove, short‑lived approvals, and formal verification. Users, on the other hand, should maintain minimal allowances, revoke unused approvals, and verify contracts before interaction. For a deeper dive into the perils of transferFrom, see Unpacking DeFi Risks: The Perilous transferFrom Feature.

Sofia Renz
Written by

Sofia Renz

Sofia is a blockchain strategist and educator passionate about Web3 transparency. She explores risk frameworks, incentive design, and sustainable yield systems within DeFi. Her writing simplifies deep crypto concepts for readers at every level.

Contents