📈 Get daily crypto insights that make you smarter about your money

Understanding Reentrancy Attacks: The Smart Contract Vulnerability That Keeps Costing Millions

On December 17, 2023, the NFT trading platform NFT Trader lost approximately $3 million in high-value NFTs to a reentrancy attack — the same class of vulnerability that famously drained The DAO of $60 million in 2016. Despite being one of the oldest and most well-documented smart contract vulnerabilities, reentrancy attacks continue to plague the crypto ecosystem, costing hundreds of millions of dollars cumulatively. This article explains what reentrancy attacks are, how they work, and how developers can prevent them, using recent real-world examples to illustrate each concept.

The Core Concept

A reentrancy attack occurs when an external contract calls back into the calling contract before the calling contract has finished updating its internal state. In simpler terms, imagine a bank withdrawal function that sends you money before deducting your balance. If you can call the withdrawal function again before the balance is updated, you can withdraw the same funds repeatedly until the contract is drained. The attack exploits the execution order of smart contracts, where external calls (sending ether or calling other contracts) can trigger callback functions that re-enter the original function.

The critical insight is that smart contract execution is synchronous within a single transaction but can involve multiple nested calls. When contract A calls contract B, contract B can call back into contract A. If contract A has not yet updated its state when contract B calls back, contract B sees the old state and can exploit the inconsistency.

Step-by-Step Breakdown

Consider the classic vulnerable contract pattern. A simple ether storage contract might have a withdraw function that first sends ether to the caller and then updates the caller’s balance. The vulnerability exists in this ordering: the external call to send ether happens before the state update that reduces the balance.

When the attacker’s contract receives the ether, its fallback function is triggered. This fallback function can call the withdraw function again. Because the balance has not yet been reduced, the contract still sees the original balance and sends more ether. This cycle continues, with each iteration sending ether before the balance is updated, until the contract is drained or the gas limit is reached.

In the NFT Trader attack, the same principle applied to NFT transfers rather than ether withdrawals. The attacker exploited a function that transferred NFTs based on approval state. By re-entering the transfer function through a callback before the approval state was cleared, the attacker could transfer the same NFTs multiple times, draining high-value assets including Bored Apes and CryptoPunks from users who had previously granted approvals to the platform.

Visualizing the Attack

Think of the attack flow as a loop. The attacker calls the vulnerable function. The function performs an external call to the attacker’s contract. The attacker’s contract calls the vulnerable function again. The function has not yet reached the state update, so it processes the second call as if the first had not happened. This creates a recursive loop where each iteration extracts value before the contract can update its records. The loop terminates when either the contract runs out of funds or the transaction runs out of gas.

The key technical detail is that the Ethereum Virtual Machine processes calls in a depth-first manner. When contract A calls contract B, contract B executes completely (including any calls back to A) before control returns to A and it continues executing. This means the re-entrant call executes while A is still in the middle of its function execution, before reaching the state update lines.

Mitigation Strategies

The most fundamental defense is the checks-effects-interactions pattern. This pattern requires that all condition checks happen first, all state modifications happen second, and all external interactions happen last. By reordering the vulnerable withdraw function to update the balance before sending the ether, the reentrancy opportunity is eliminated because the balance is already zero when the attacker tries to withdraw again.

A more explicit defense is the reentrancy guard modifier, popularized by OpenZeppelin’s ReentrancyGuard contract. This modifier uses a status variable that is set to indicate a function is currently executing. If the function is called again before the first call completes, the modifier rejects the call. This provides a simple, reliable lock mechanism that prevents any reentrant calls regardless of the specific function logic.

For more complex contracts, the pull-over-push pattern can eliminate the need for external calls entirely. Instead of sending funds proactively, contracts record that a user is entitled to withdraw and let the user initiate the withdrawal themselves. This shifts the external call to a separate transaction, making reentrancy impossible within a single call.

Lessons From Recent Exploits

The persistence of reentrancy vulnerabilities in 2023 highlights several systemic issues in smart contract development. First, the rush to ship features often leads teams to skip thorough security reviews of their contract logic. Second, even experienced developers can introduce reentrancy through complex state interactions that are not immediately obvious during code review. Third, the increasing complexity of DeFi protocols, with their composability and cross-contract interactions, creates new reentrancy surfaces that were not present in simpler contracts.

The NFT Trader attack specifically exploited a reentrancy in an NFT transfer function, a pattern that is less commonly discussed than the classic ether withdrawal reentrancy. This illustrates an important lesson: reentrancy can occur in any context where an external call is made before state is updated, not just in withdrawal functions. Developers must audit all external calls, regardless of their purpose, for potential reentrancy vulnerabilities.

Key Takeaways

Reentrancy remains one of the most expensive vulnerability classes in smart contract security. The defense is well-understood and straightforward to implement: follow the checks-effects-interactions pattern, use reentrancy guards, and consider pull-over-push patterns for fund transfers. Every external call should be treated as a potential reentrancy point and audited accordingly. The tools to prevent these attacks exist — the industry needs the discipline to use them consistently. Until then, reentrancy will continue to cost millions.

Disclaimer: This article is for educational purposes only and does not constitute financial or investment advice. Always conduct your own research before making any investment decisions.

🌱 FOR BUSINESSES BitcoinsNews.com
Reach 100K+ Crypto Readers
Sponsored content, press releases, banner ads, and newsletter placements. Put your brand in front of Bitcoin's most engaged audience.

10 thoughts on “Understanding Reentrancy Attacks: The Smart Contract Vulnerability That Keeps Costing Millions”

  1. the DAO hack was 2016 and people are still shipping the same bug in 2023. checks-effects-interactions is literally day 1 of any solidity tutorial

    1. the DAO hack used the exact same pattern in 2016 and we’re still seeing it in 2023. OpenZeppelin’s ReentrancyGuard is literally a 5 line import, no excuse

    2. checks-effects-interactions is literally taught in solidity lesson 1. how do professional auditors still miss this

      1. audit_grind_ the problem isnt that auditors miss it, its that projects skip audits entirely to save money. NFT Trader probably spent more on marketing than security

    1. the reentrancy guard modifier costs like 20k gas. thats literally pennies to prevent a $3M exploit. the ROI on basic security is absurd

    2. the bank analogy is perfect. imagine withdrawing cash and the teller forgets to deduct from your balance. same exact bug

  2. NFT Trader losing 3M to the same bug class that drained The DAO in 2016. seven years later and people still dont implement checks-effects-interactions properly. embarrassing

    1. kol_n the bank withdrawal analogy in the article is perfect. if you send money before updating the balance you deserve to get drained. this is day one Solidity stuff

  3. ReentrancyGuard from OpenZeppelin prevents this with one modifier. there is no excuse for any contract in 2023 to be vulnerable. use the tools that exist

Leave a Comment

Your email address will not be published. Required fields are marked *

BTC$66,505.00+1.3%ETH$1,782.89+3.7%SOL$74.79+4.8%BNB$615.83-0.1%XRP$1.24+5.0%ADA$0.1790-1.1%DOGE$0.0882-0.7%DOT$1.02+2.0%AVAX$6.97+2.8%LINK$8.33+1.5%UNI$2.97+13.8%ATOM$1.99+1.3%LTC$45.95+1.7%ARB$0.0867-0.1%NEAR$2.47+3.4%FIL$0.8021+0.0%SUI$0.8007+0.6%BTC$66,505.00+1.3%ETH$1,782.89+3.7%SOL$74.79+4.8%BNB$615.83-0.1%XRP$1.24+5.0%ADA$0.1790-1.1%DOGE$0.0882-0.7%DOT$1.02+2.0%AVAX$6.97+2.8%LINK$8.33+1.5%UNI$2.97+13.8%ATOM$1.99+1.3%LTC$45.95+1.7%ARB$0.0867-0.1%NEAR$2.47+3.4%FIL$0.8021+0.0%SUI$0.8007+0.6%
Scroll to Top