A reentrancy attack is a class of smart contract vulnerability in which a malicious contract exploits an external function call to re-enter the calling contract before the original execution has completed, allowing the attacker to repeatedly drain funds or manipulate state variables. The attack occurs when a contract sends Ether or tokens to an external address, typically using the low-level call method, before updating its own internal state, creating a window during which the recipient’s fallback or receive function can recursively call back into the vulnerable contract.
The canonical mechanism works as follows: a victim contract holds a balance mapping and a withdraw function. When a user calls withdraw, the contract sends Ether to the caller’s address before setting their balance to zero. If the caller is a malicious contract with a fallback function that immediately calls withdraw again, the victim contract’s balance check still shows the original amount because the state update has not yet occurred. This recursive re-entry continues draining funds until the victim contract’s Ether balance is exhausted or the call stack limit is reached.
Reentrancy attacks exploit the fundamental property of the Ethereum Virtual Machine (EVM) that external calls transfer execution control to the callee before the caller’s subsequent instructions execute. This makes reentrancy one of the most dangerous and well-studied vulnerabilities in smart contract development. The pattern has been responsible for some of the largest financial losses in decentralized finance history, including the infamous DAO hack of 2016 that resulted in approximately $60 million in losses and ultimately led to the Ethereum hard fork that created Ethereum Classic.
Modern reentrancy variants extend beyond the simple single-function pattern to include cross-function reentrancy (where the callback re-enters a different function that reads the stale state), cross-contract reentrancy (where the callback targets a different contract that shares state with the vulnerable one), and read-only reentrancy (where the callback exploits stale state in view functions used by other protocols for pricing or collateral calculations).
Origin & History
2015: Ethereum launched with Solidity as its primary smart contract language. The EVM’s design, where external calls transfer execution control and allow arbitrary code execution by the callee, created the foundational conditions for reentrancy vulnerabilities. Early Solidity documentation did not prominently warn about the risks of making external calls before state updates.
June 2016: The DAO, a decentralized autonomous organization that had raised approximately $150 million in ETH through a token sale, was exploited through a reentrancy vulnerability in its splitDAO function. An attacker deployed a malicious contract with a crafted fallback function that called back into The DAO’s splitDAO function recursively, draining approximately 3.6 million ETH (worth around $60 million at the time). This remains the most consequential reentrancy attack in blockchain history.
July 2016: The Ethereum community faced a governance crisis over whether to hard fork the blockchain to reverse the DAO hack. This event put the “code is law” principle, the founding premise of The DAO, to an ultimate test. The majority of the community, supported by Vitalik Buterin, favored a conditional interpretation of the principle, executing a hard fork at block 1,920,000 to recover funds. Opponents, asserting that “code is law” must be absolute and immutable, continued the original chain as Ethereum Classic (ETC).
2017-2018: The DAO hack catalyzed a security-first approach to smart contract development. OpenZeppelin released its ReentrancyGuard contract, providing a standardized mutex-based protection against reentrancy. Formal verification tools and security auditing firms like Trail of Bits and ConsenSys Diligence emerged to address the growing need for smart contract security.
2020: The DeFi Summer explosion brought billions of dollars into smart contracts, dramatically raising the stakes for reentrancy vulnerabilities. The composability of DeFi protocols (“money legos”) introduced cross-contract reentrancy risks that were harder to detect and audit than single-contract vulnerabilities.
April 2020: The Uniswap/Lendf.me incident saw approximately $25 million drained across both platforms through a reentrancy attack exploiting ERC-777 token callbacks, with Lendf.me (dForce’s lending protocol) accounting for the vast majority of losses at roughly $24.5 million. This demonstrated that reentrancy was not limited to raw ETH transfers but could be triggered by token standard callback mechanisms.
July 2023: Curve Finance suffered a devastating reentrancy attack due to a compiler bug in Vyper (versions 0.2.15, 0.2.16, and 0.3.0) that caused the reentrancy lock to malfunction. Multiple Curve pools were drained for approximately $70 million, proving that reentrancy defenses could fail at the language compiler level, not just at the contract logic level.
2024-2026: Read-only reentrancy emerged as a new frontier of concern, particularly in protocols that rely on other contracts’ view functions for pricing. Cross-chain reentrancy risks also materialized as bridge protocols and multi-chain DeFi architectures created new attack surfaces where state inconsistencies between chains could be exploited.
“The DAO hack was the moment the Ethereum community learned that code is law, but law can have bugs. It fundamentally changed how we think about smart contract security forever.”
In Simple Terms
Imagine you have a bank teller who checks your account balance, hands you cash, and then updates the ledger to reflect the withdrawal. A reentrancy attack is like running back to the same teller before they update the ledger and asking for another withdrawal. The teller still sees your original balance and hands you more cash. You keep running back until the vault is empty.
Think of a vending machine that dispenses a drink, then deducts money from your prepaid card. If you could press the button again the instant the drink starts coming out, but before the card is debited, you would get multiple drinks for the price of one. The reentrancy attack exploits this gap between “give the thing” and “record that I gave the thing.”
Picture a revolving door at a hotel. Normally, you walk through, the doorman marks your entry, and you proceed inside. In a reentrancy attack, you step into the revolving door, and before the doorman can mark your entry, you spin back around and enter again, and again and again, each time appearing as a “new” visitor because the doorman never got to update his list.
It is like a checkout line where the cashier hands you your groceries before scanning them. If you could loop back to the front of the line instantly with the same cart, the cashier would keep handing you more groceries because the register still shows your full payment. Eventually, the store runs out of inventory.
Important: Reentrancy attacks target the contract code itself, not the blockchain’s consensus mechanism. The blockchain faithfully records every transaction, including the malicious ones. This is why prevention must happen at the smart contract development level through secure coding patterns, audits, and formal verification. The blockchain cannot distinguish between a legitimate withdrawal and a reentrancy exploit.
Key Technical Features
The Reentrancy Mechanism in Detail
The attacker deploys a malicious contract with a specially crafted fallback (or receive) function
The attacker calls the vulnerable contract’s withdraw function from the malicious contract
The vulnerable contract checks the attacker’s balance. It passes because the attacker has deposited funds
The vulnerable contract sends ETH to the attacker’s contract address using a low-level call with value
Before execution returns to the vulnerable contract’s next line (the balance update), the EVM transfers control to the attacker’s contract
The attacker’s fallback function executes automatically upon receiving ETH and immediately calls withdraw again
The vulnerable contract re-executes the withdraw function. Because the balance has not been updated, the check passes again
Steps 4 through 7 repeat recursively until the contract’s ETH balance is depleted or the gas limit is reached
Only after the final recursive call completes does the call stack unwind, and the balance update from the first call finally executes. But the funds are already gone
The Checks-Effects-Interactions Pattern
Checks: Validate all conditions and requirements (e.g., require(balances[msg.sender] >= amount))
Effects: Update all internal state variables (e.g., balances[msg.sender] -= amount)
Interactions: Perform external calls (e.g., msg.sender.call{value: amount}("")) only after all state changes
This ordering ensures that even if a reentrant call occurs during the interaction step, the state has already been updated, and subsequent balance checks will fail. This pattern is the single most important defense against reentrancy and is mandated by all major Solidity style guides and audit firms.
OpenZeppelin ReentrancyGuard
Provides a nonReentrant modifier that uses a mutex (mutual exclusion) variable to prevent re-entry
The modifier sets a status lock before function execution and resets it after completion
If a reentrant call attempts to execute the protected function while the lock is active, the transaction reverts
Implementation uses a uint256 status variable (1 = not entered, 2 = entered) rather than a boolean for gas optimization
Widely adopted across DeFi: Aave, Compound, Uniswap V3, and hundreds of other protocols use ReentrancyGuard or equivalent patterns
Reentrancy Variants
Single-function reentrancy: The classic attack where the fallback function calls back into the same vulnerable function. This was the DAO hack pattern
Cross-function reentrancy: The fallback function calls a different function in the same contract that reads the stale state variable, allowing exploitation through a secondary path
Cross-contract reentrancy: The callback targets a different contract that shares state or trust relationships with the vulnerable contract, exploiting composability in DeFi
Read-only reentrancy: The callback calls a view function that returns stale state, which is then used by a third-party protocol for pricing, collateral valuation, or oracle feeds. No direct fund drain occurs, but indirect exploitation is enabled
ERC-777 reentrancy: The ERC-777 token standard includes callback hooks (tokensReceived) that execute code on the recipient, creating reentrancy vectors in protocols that handle ERC-777 tokens without protection
Detection and Prevention Tools
Static analysis: Tools like Slither (by Trail of Bits) automatically detect reentrancy patterns in Solidity code through control flow analysis
Formal verification: Tools like Certora Prover mathematically verify that reentrancy is impossible given a contract’s specification
Fuzzing: Echidna and Foundry’s forge fuzz test contracts with random inputs to discover reentrancy and other vulnerabilities
Security audits: Professional audit firms (Trail of Bits, OpenZeppelin, Consensys Diligence, Halborn) manually review contract code for reentrancy and other vulnerabilities
Bug bounties: Platforms like Immunefi incentivize white-hat hackers to discover reentrancy vulnerabilities before malicious actors exploit them
Advantages & Disadvantages
Advantages (of Understanding Reentrancy)
Disadvantages (Risks of Reentrancy)
Security Awareness: Understanding reentrancy is foundational to writing secure smart contracts. It is the first vulnerability taught in every Solidity security course
Catastrophic Financial Loss: A single reentrancy exploit can drain an entire protocol’s funds in a single transaction, as demonstrated by the $60M DAO hack and $70M Curve exploit
Established Defenses: Well-documented mitigation patterns (checks-effects-interactions, ReentrancyGuard) make reentrancy preventable when developers follow best practices
Evolving Attack Vectors: New variants like read-only reentrancy and cross-contract reentrancy continue to emerge, outpacing developer awareness and existing detection tools
Tool Ecosystem: A strong ecosystem of static analyzers, fuzzers, and formal verification tools can automatically detect most reentrancy patterns before deployment
Compiler-Level Risks: The 2023 Curve Finance exploit proved that reentrancy defenses can fail due to bugs in the compiler itself, creating a risk layer beyond developer control
Audit Industry Growth: The prevalence of reentrancy has driven the growth of a professional smart contract auditing industry, improving overall ecosystem security
Composability Amplification: DeFi’s composable “money lego” architecture means a reentrancy vulnerability in one protocol can cascade across multiple interconnected protocols
Community Knowledge Sharing: High-profile reentrancy exploits have generated extensive post-mortem analyses, open-source educational resources, and industry-wide security improvements
False Sense of Security: Developers who apply ReentrancyGuard to some functions may miss cross-function or cross-contract reentrancy paths, creating incomplete protection
Bug Bounty Incentives: The severity of reentrancy has led protocols to offer substantial bug bounties (often $1M+), incentivizing white-hat discovery over black-hat exploitation
Gas Overhead: Reentrancy guards add gas costs to every protected function call, which compounds across high-frequency DeFi operations and can impact protocol competitiveness
Governance Lessons: The DAO hack taught the blockchain community critical lessons about governance, immutability, and the social layer’s role in responding to code-level failures
Irreversibility of Exploits: Unlike traditional finance where fraudulent transactions can be reversed, reentrancy exploits on immutable blockchains are permanent unless the community agrees to a contentious hard fork
Risk Management
Smart Contract Development Practices
Always follow the checks-effects-interactions pattern: update all state variables before making any external calls
Apply OpenZeppelin’s nonReentrant modifier to every function that performs external calls or transfers value
Avoid using transfer() and send() for ETH transfers in new contracts. While they limit gas to 2,300 (preventing some reentrancy), they can break with EIP changes and gas repricing
Use pull-over-push payment patterns: instead of sending funds directly, allow users to withdraw their own funds, reducing the attack surface
Audit and Testing Protocols
Require at least two independent security audits from reputable firms before deploying contracts that handle significant value
Run Slither and Mythril static analysis on every contract before deployment. These tools flag the most common reentrancy patterns automatically
Implement detailed fuzz testing suites using Echidna or Foundry that specifically target reentrancy scenarios
Conduct cross-contract reentrancy analysis when integrating with external protocols, especially those using callback-heavy token standards like ERC-777
Operational Security
Deploy contracts behind upgradeable proxy patterns or with emergency pause mechanisms that can halt withdrawals if reentrancy is detected
Monitor on-chain activity for unusual withdrawal patterns (e.g., rapid recursive calls to the same function within a single transaction) using tools like Forta or OpenZeppelin Defender
Establish incident response procedures, including contract pausing, communication channels, and fund recovery strategies
Maintain bug bounty programs with payouts proportional to the total value locked (TVL) in the protocol
DeFi Integration Risk
When composing with external protocols, audit the external contract’s reentrancy protections before integrating
Do not assume that external view functions return a consistent state during callback execution. This is the read-only reentrancy vector
Implement reentrancy guards at the protocol boundary level, not just at the individual function level, to prevent cross-contract reentrancy chains
Cultural Relevance
The reentrancy attack holds a unique position in blockchain culture as the event that shattered the naive “code is law” philosophy and forced the Ethereum community to confront the tension between immutability and pragmatism. The DAO hack of 2016 was not merely a technical exploit. It was an existential moment for Ethereum that divided the community into two philosophical camps, one of which forked into Ethereum Classic.
“The DAO was supposed to prove that decentralized governance could work. Instead, it proved that writing secure code is harder than anyone imagined.”
In developer culture, reentrancy has become a rite of passage. Every Solidity developer’s education begins with studying the DAO hack, and “have you checked for reentrancy?” is the most frequently asked question in smart contract code reviews. The Damn Vulnerable DeFi and Ethernaut capture-the-flag challenges both feature reentrancy levels as foundational exercises.
The Curve Finance exploit of July 2023 reignited cultural discourse around reentrancy, this time focused on the prospect that compiler-level bugs could undermine defenses that developers implemented correctly. The Vyper compiler bug that disabled reentrancy locks demonstrated that security in smart contract development requires trust not just in one’s own code, but in the entire toolchain. That lesson resonated deeply with the blockchain community’s ethos of minimal trust assumptions.
On crypto Twitter and DeFi forums, reentrancy exploits are analyzed in real-time with the intensity of breaking news events. White-hat hackers who discover and responsibly disclose reentrancy vulnerabilities are celebrated as community heroes, while post-mortem analyses of exploits become some of the most widely shared technical content in the ecosystem. The phrase “reentrancy” has transcended its technical definition to become a cultural shorthand for the ever-present tension between innovation speed and security rigor in decentralized finance.
Real-World Examples
The DAO Hack (June 2016)
Scenario: The DAO, a decentralized venture capital fund, held approximately $150 million worth of ETH contributed by thousands of investors. Its splitDAO function allowed investors to withdraw their proportional share of funds into a “child DAO.”
Implementation: An attacker deployed a malicious external contract with a fallback function designed to recursively call back into The DAO’s splitDAO function. That function sent ETH to the attacker’s contract before updating the internal balance. Because the balance was never zeroed between recursive calls, the attacker continued draining funds over several hours, extracting approximately 3.6 million ETH (around $60 million).
Outcome: The Ethereum community executed a hard fork at block 1,920,000 to restore the stolen funds, creating the Ethereum (ETH) and Ethereum Classic (ETC) split. This event established reentrancy as the most infamous vulnerability in smart contract history and catalyzed the entire smart contract security industry.
Curve Finance Vyper Exploit (July 30, 2023)
Scenario: Multiple Curve Finance liquidity pools (alETH/ETH, msETH/ETH, pETH/ETH, and CRV/ETH) were built with Vyper smart contracts that included @nonreentrant decorators, the Vyper equivalent of Solidity’s ReentrancyGuard.
Implementation: A bug in Vyper compiler versions 0.2.15, 0.2.16, and 0.3.0 caused the @nonreentrant lock to be incorrectly compiled, effectively disabling the reentrancy protection at runtime despite it appearing correctly in the source code. Attackers exploited this to re-enter pool functions during liquidity removal, manipulating prices and draining funds. The exploit targeted the remove_liquidity function, which sent tokens to the caller before fully updating pool state.
Outcome: Approximately $70 million was drained across multiple pools. Several white-hat hackers and MEV bots front-ran some of the attacks, recovering a portion of the funds. The incident exposed the critical risk of compiler-level bugs undermining application-level security measures and led to a detailed audit of the Vyper compiler.
Uniswap/Lendf.me ERC-777 Attack (April 2020)
Scenario: dForce’s Lendf.me protocol, a lending platform, supported imBTC, an ERC-777 token with built-in callback hooks. When a user received imBTC tokens, the ERC-777 tokensReceived hook executed code on the recipient’s contract. Uniswap was also targeted in a related attack, with combined losses across both platforms reaching approximately $25 million, the overwhelming majority coming from Lendf.me.
Implementation: The attacker exploited the tokensReceived callback during the supply function: when Lendf.me sent imBTC to the attacker’s contract as part of a supply/borrow operation, the callback re-entered Lendf.me’s supply function, artificially inflating the attacker’s collateral balance. With the inflated collateral, the attacker borrowed all available assets from the protocol.
Outcome: Approximately $24.5 million was drained from Lendf.me specifically, with smaller losses from Uniswap. The attacker eventually returned the funds after being partially identified. This incident highlighted the reentrancy risks specific to ERC-777 token callbacks and led many DeFi protocols to explicitly blacklist or add guards for callback-enabled token standards.
Rari Capital / Fei Protocol Exploit (April 2022)
Scenario: Rari Capital’s Fuse lending pools allowed users to supply and borrow various tokens. Several Fuse pools accepted tokens with callback mechanisms that enabled reentrancy during the borrow flow.
Implementation: The attacker used a reentrancy vulnerability in the borrow function’s interaction with callback-enabled tokens. By re-entering during the borrow callback, the attacker manipulated the pool’s accounting to borrow more than their collateral permitted, repeating the process across multiple Fuse pools.
Outcome: Approximately $80 million was stolen across multiple Fuse pools. Rari Capital and Fei Protocol, which had recently merged, were unable to recover the funds, ultimately leading to the protocol’s wind-down. The exploit underscored the risks of reentrancy in composable lending protocols with permissive token whitelisting.
Comparison Table
Feature
Reentrancy Attack
Flash Loan Attack
Oracle Manipulation Attack
Attack Vector
Recursive external calls before state updates
Uncollateralized loans exploiting protocol logic within a single transaction
Feeding false price data to smart contracts via manipulated or stale oracles
Root Cause
Violation of the checks-effects-interactions pattern
Protocol logic that assumes borrowers have real capital at risk
Reliance on single-source or easily manipulable price feeds
Capital Required
Minimal (just enough to trigger the first withdrawal)
Zero (flash loans are uncollateralized by design)
Variable (from zero with flash loans to significant for direct market manipulation)
High: distinguishing manipulation from legitimate market activity is inherently difficult
Blockchain Impact
Caused the Ethereum hard fork (ETH/ETC split)
Drove innovation in MEV protection and transaction ordering
Led to widespread Chainlink adoption and TWAP oracle standards
Related Terms
Smart Contract: Self-executing programs deployed on a blockchain that automatically enforce agreement terms. Reentrancy exploits target vulnerabilities in smart contract logic.
The DAO: A decentralized autonomous organization on Ethereum that suffered the most famous reentrancy attack in 2016, leading to the ETH/ETC hard fork.
Fallback Function: A special Solidity function that executes when a contract receives ETH or an unrecognized function call. The mechanism through which reentrancy callbacks are triggered.
Checks-Effects-Interactions Pattern: A secure coding pattern that mandates performing all state updates before external calls, preventing reentrancy by design.
OpenZeppelin: The leading open-source smart contract library providing battle-tested security primitives, including ReentrancyGuard, used by most major DeFi protocols.
Flash Loan: An uncollateralized loan that must be borrowed and repaid within a single transaction. Often combined with reentrancy or other exploit techniques for maximum impact.
Ethereum Classic (ETC): The continuation of the original Ethereum chain that refused to fork after the DAO hack, preserving the chain where the reentrancy exploit remained unreversed.
Formal Verification: Mathematical proof that a smart contract behaves according to its specification. Can definitively prove the absence of reentrancy vulnerabilities.
ERC-777: An advanced token standard with built-in callback hooks that introduced new reentrancy attack surfaces in DeFi protocols.
Mutex (Mutual Exclusion): A concurrency control mechanism adapted for smart contracts in the form of reentrancy guards that prevent simultaneous execution of protected functions.
Vyper: A Python-like smart contract language for the EVM. A Vyper compiler bug caused the 2023 Curve Finance reentrancy exploit despite correct application-level protections.
MEV (Maximal Extractable Value): The value that block producers can extract by reordering transactions. MEV bots sometimes front-run reentrancy exploits to capture or return stolen funds.
FAQ
Q: What exactly is a reentrancy attack in simple terms?
A reentrancy attack happens when a smart contract sends money to an external address before recording that the money was sent. The recipient can be a malicious contract that immediately asks for more money, and because the record hasn’t been updated yet, the vulnerable contract thinks the attacker still has their original balance. This loops repeatedly, draining the contract’s funds.
Q: How did the DAO hack work, and why was it so significant?
The DAO was a $150 million investment fund on Ethereum. Its splitDAO withdrawal function sent ETH to users before updating their balance to zero. An attacker deployed a malicious contract whose fallback function called back into splitDAO each time it received ETH, recursively draining approximately $60 million. The hack was so significant that the Ethereum community hard-forked the entire blockchain to reverse it, splitting Ethereum into ETH and Ethereum Classic — a defining moment in blockchain governance history.
Q: Can reentrancy attacks happen on blockchains other than Ethereum?
Yes. Reentrancy is possible on any blockchain that supports smart contracts with external calls that transfer execution control. This includes EVM-compatible chains like BNB Chain, Polygon, Avalanche, and Arbitrum. Non-EVM chains like Solana have different execution models that make traditional reentrancy harder but not impossible. Solana’s runtime prevents recursive CPI (cross-program invocation) calls to the same program within a single instruction, but cross-program reentrancy-like patterns can still occur.
Q: What is the checks-effects-interactions pattern, and how does it prevent reentrancy?
The checks-effects-interactions pattern is a coding discipline that requires three steps in strict order: first, check all conditions (e.g., does the user have sufficient balance?); second, update all state variables (e.g., reduce the user’s balance to zero); third, interact with external contracts (e.g., send ETH). By updating state before the external call, any reentrant callback will encounter the already-updated state and fail its check, preventing the exploit.
Q: What is read-only reentrancy, and why is it dangerous?
Read-only reentrancy occurs when a callback during an external call allows an attacker to read stale state from view functions. Even though no funds are directly drained from the vulnerable contract, other protocols that rely on those view functions for pricing, collateral calculations, or oracle data will receive incorrect values. This can be exploited to take undercollateralized loans or manipulate prices in connected DeFi protocols, making it a subtle but potentially devastating attack vector.
Q: How did the 2023 Curve Finance exploit happen despite having reentrancy guards?
Curve Finance’s pools were written in Vyper and correctly used the @nonreentrant decorator to prevent reentrancy. However, a bug in Vyper compiler versions 0.2.15, 0.2.16, and 0.3.0 caused the reentrancy lock to be incorrectly compiled — the lock was never actually set during execution, even though it appeared correctly in the source code. This meant the reentrancy guard existed on paper but was silently removed during compilation. The exploit demonstrated that smart contract security depends not only on correct application code but on the correctness of the entire toolchain, including the compiler.
Q: What tools can developers use to detect reentrancy vulnerabilities before deployment?
Developers should use a layered approach: (1) static analysis tools like Slither and Mythril that automatically scan code for reentrancy patterns, (2) fuzz testing with Echidna or Foundry forge that test contracts with randomized inputs, (3) formal verification with tools like Certora Prover that mathematically prove the absence of reentrancy, and (4) professional security audits from firms like Trail of Bits, OpenZeppelin, or Halborn. No single tool catches all variants, so a defense-in-depth strategy is essential.