Approvals are a fundamental component of tokens on Ethereum. They allow users to grant permission to third-party addresses, be it externally owned accounts (EOAs) or other smart contracts, to move funds on their behalf. This feature has benefited many systems, including NFT marketplaces and DeFi applications. These platforms often employ approvals to automate the transfer of funds. This could be when a trade is completed or funds must be moved based on specific business logic conditions.
A prevalent misstep among smart contract developers is requiring unlimited approvals for certain assets. This is usually justified by the system’s lack of knowledge of the necessary amount at a given time. This implies the following problem: Once granted, approvals can be invoked anytime. If a malicious party were to compromise the smart contract system, they could exploit these approvals, leading to a complete drain of all previously approved assets for the affected address.
Another issue is the susceptibility of the approval system to frontrunning. When a user submits multiple
approve calls, they inadvertently open a window of opportunity for malicious actors. To illustrate:
- Using the
approvefunction, a user allows a smart contract system to transfer
xof their ERC20 tokens.
- Later, they opt to modify the allowance to
yand thus send another
- In the meantime, before the user-given transaction gets included, an attacker initiates the
transferFromfunction to remove
xtokens from the user’s wallet.
- If the attacker’s transaction is processed first, followed by the user's new
approvetransaction, the malicious actor can move an additional
- The aggregate unauthorized transfer would amount to
This vulnerability arises because the ERC20's
_approve function directly sets the spender’s allowance.
1 2 3 4 5 6 7 8 9 10 11 12
_spendAllowance function only verifies the current allowance against the amount specified in the
transferFrom call. It lacks a mechanism to track funds transferred before the latest
1 2 3 4 5 6 7 8 9 10 11
Security Best Practices for Approvals¶
One straightforward countermeasure against frontrunning is to modify how the allowance is managed. Rather than arbitrarily increasing or decreasing allowances by setting new values with direct
approve calls, it’s best practice to call the
safeDecreaseAllowance functions, as defined in OpenZeppelin's SafeERC20 implementation. These functions internally call the target's
approve function but offer an additional parameter specifying the value difference.
Another notable threat, although not a direct, smart contract vulnerability, is "approval phishing." In scenarios where a frontend is exposed to content injection attacks or other manipulations, attackers can modify the underlying code to divert approvals not to the intended smart contract address but to their own, hijacking the process.
Developers should employ an allowance system that limits the number of tokens an approval can move to only the immediately necessary amount. Implementing two-step transfers and locking periods can limit the impact of malicious actions, although this might reduce user-friendliness. For users, a good habit is periodically assessing given approvals and revoking outdated or unnecessary ones. There are platforms like https://revoke.cash/ that can help in this regard.