Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Glossary

Reentrancy Attack

A reentrancy attack is a critical smart contract vulnerability where a malicious contract exploits a state update race condition to drain funds.
Chainscore © 2026
definition
SECURITY VULNERABILITY

What is a Reentrancy Attack?

A reentrancy attack is a critical smart contract vulnerability where an external malicious contract exploits a state update delay to repeatedly call back into a vulnerable function, draining its funds.

A reentrancy attack is a security exploit in which a malicious contract recursively calls back into a vulnerable function before its initial execution and state updates are complete. This is made possible by the attacker's fallback() or receive() function, which is triggered when the vulnerable contract sends Ether, creating a loop. The classic pattern involves a contract that checks a user's balance, sends them Ether, and then updates the internal balance state. An attacker can intercept the send operation and call the vulnerable function again, passing the initial balance check repeatedly and draining the contract's funds in a single transaction.

The most famous real-world example is the 2016 DAO attack on Ethereum, which exploited a reentrancy vulnerability to drain approximately 3.6 million ETH. The attack utilized the same recursive callback mechanism, highlighting the catastrophic financial consequences of this flaw. Developers prevent reentrancy by adhering to the Checks-Effects-Interactions pattern, which mandates that state changes (effects) are finalized before any external calls (interactions). Another robust mitigation is using reentrancy guards, such as OpenZeppelin's ReentrancyGuard modifier, which employs a mutex lock to block recursive calls.

Beyond the basic single-function attack, variations exist, including cross-function reentrancy, where the callback targets a different function that shares state with the vulnerable one, and read-only reentrancy, which manipulates oracle or price feed data during a callback. These sophisticated attacks underscore that security must be considered across the entire contract system, not just individual functions. Auditing tools and formal verification can help identify potential reentrancy paths, but the primary defense remains rigorous development practices that treat all external calls as untrusted and manage state with extreme caution.

how-it-works
BLOCKCHAIN SECURITY

How a Reentrancy Attack Works

A technical breakdown of the exploit mechanism that allows a malicious contract to repeatedly call back into a vulnerable function before its initial execution completes.

A reentrancy attack is a critical vulnerability in smart contracts where an external malicious contract exploits the state update pattern of a target contract to drain its funds. The attack hinges on a contract making an external call to an untrusted address before updating its own internal state, such as a user's balance. The malicious contract, acting as the recipient, contains a fallback function or receive function that is automatically executed upon receiving funds, and this function is designed to recursively call back into the vulnerable function of the original contract.

The classic example is the 2016 DAO hack, where the attacker's contract exploited a withdraw function. The vulnerable function would send Ether first and then update the sender's balance to zero. The attacker's fallback function would repeatedly call withdraw again before the balance was deducted, creating a recursive loop. Because the contract's state (the attacker's stored balance) remained unchanged during each call, the function continued to send funds, allowing the attacker to drain the contract over multiple iterations in a single transaction.

To prevent reentrancy, developers employ several key patterns. The most fundamental is the Checks-Effects-Interactions (CEI) pattern, which mandates the order of operations: first perform all checks (e.g., sufficient balance), then update all internal effects (e.g., deduct the balance), and only finally make external interactions (e.g., sending Ether). Another robust defense is using reentrancy guards, such as OpenZeppelin's ReentrancyGuard modifier, which employs a boolean lock (nonReentrant) to prevent a function from being entered while it is already executing.

Beyond simple Ether transfers, reentrancy can manifest in cross-function and cross-contract forms. In cross-function reentrancy, a call from a malicious contract re-enters a different function in the same vulnerable contract that shares state. Cross-contract reentrancy involves two contracts that share state, where an exploit in one affects the other. These variants are more subtle and harder to detect than the classic single-function attack, requiring thorough state machine analysis during audits.

Understanding reentrancy is essential for secure smart contract development. It exemplifies the Ethereum Virtual Machine (EVM)'s synchronous execution model and the dangers of external calls. Auditing tools and formal verification often flag potential reentrancy, but manual code review focusing on state changes relative to call, transfer, or send operations remains crucial. This vulnerability fundamentally shaped modern smart contract security practices and library design.

key-features
SECURITY PATTERN

Key Characteristics of Reentrancy

Reentrancy is a programming pattern where a function can be interrupted mid-execution and called again before its initial invocation completes, a mechanism that becomes a critical vulnerability in smart contracts when combined with external calls and state updates.

01

The Core Vulnerability

A reentrancy attack exploits the pattern where a smart contract makes an external call to an untrusted contract before updating its own internal state. The malicious contract's fallback or receive function recursively calls back into the vulnerable function, potentially draining funds. The classic example is The DAO hack of 2016, which resulted in the loss of 3.6 million ETH.

02

State Update Order (Checks-Effects-Interactions)

The primary defense is the Checks-Effects-Interactions (CEI) pattern. This mandates a strict execution order:

  • Checks: Validate all conditions (e.g., balances, permissions).
  • Effects: Update all internal state variables (e.g., deduct balances).
  • Interactions: Perform external calls to other contracts or addresses. By updating state before making external calls, you eliminate the inconsistent state that reentrancy attacks depend on.
03

Reentrancy Guard Modifier

A reentrancy guard is a code-level mutex that uses a boolean state variable (e.g., locked) to prevent recursive calls. The OpenZeppelin ReentrancyGuard contract provides a nonReentrant modifier that throws if a reentrant call is detected. This is a robust, generalized solution but adds minor gas overhead and should not replace careful state management with the CEI pattern.

04

Single-Function vs. Cross-Function

Reentrancy attacks are categorized by their scope:

  • Single-Function Reentrancy: The malicious callback re-enters the same function it was called from. This is prevented by CEI or a guard.
  • Cross-Function Reentrancy: The callback targets a different function in the same contract that shares state with the first. This is more subtle and requires ensuring all related functions that share critical state are also protected.
05

Interaction with Withdrawal Patterns

The pull-over-push withdrawal pattern is a key design strategy to mitigate reentrancy. Instead of a contract actively "pushing" funds to users (which requires an external call), users initiate a "pull" transaction to withdraw their owed funds. This inverts the trust model, placing the gas cost and transaction initiation on the user and removing the vulnerable external call from the core contract logic.

06

Formal Verification & Static Analysis

Tools for static analysis (like Slither or MythX) and formal verification (using tools like Certora Prover or the SMTChecker in Solidity) can automatically detect potential reentrancy vulnerabilities by analyzing control flow and state dependencies. These are essential components of a professional smart contract security toolkit, complementing manual audits and testing.

code-example
REENTRANCY ATTACK

Code Example: A Vulnerable Contract

A practical demonstration of a smart contract vulnerability where an external call allows an attacker to recursively drain funds before state updates are finalized.

A classic reentrancy vulnerability occurs when a contract's function makes an external call to an untrusted address before it updates its own internal state, such as a user's balance. The infamous DAO hack exploited this pattern. In the vulnerable code, a withdraw() function might send Ether via .call.value() to msg.sender and then subtract the amount from the sender's stored balance. This sequence creates a critical window where the contract's logic is suspended mid-execution, allowing a malicious contract to re-enter the vulnerable function.

The attack is executed by a malicious contract, often called an attacker contract or reentrancy exploit contract, that implements a receive() or fallback() function. When the vulnerable contract sends Ether, it triggers this function in the attacker's contract. Within this callback, the attacker can call back into the original vulnerable function—hence reentrancy—before the first invocation has completed its state update. This recursive loop continues, draining funds in multiple transactions until the gas limit is reached or the contract's balance is depleted.

To prevent this, developers must adhere to the Checks-Effects-Interactions pattern. This security principle mandates a strict order of operations: first, perform all checks (e.g., validating balances); second, apply all effects (e.g., updating internal state variables); and only then, perform external interactions (e.g., sending Ether or calling other contracts). By updating the balance before the external call, the reentrant call will fail the initial check, as the balance has already been set to zero, blocking the recursive drain.

Modern Solidity developers should also utilize built-in protections. Using transfer() or send() for Ether transfers, which limit forwarded gas to 2300 units, can mitigate simple reentrancy, as this is insufficient for complex callback logic. However, the most robust solution is to use reentrancy guards, such as OpenZeppelin's ReentrancyGuard modifier, which employs a mutex lock (nonReentrant) to prevent a function from being called recursively within the same transaction.

Analyzing vulnerable code is crucial for security auditing. A typical flawed function signature might be function withdraw(uint _amount) public { require(balances[msg.sender] >= _amount); msg.sender.call.value(_amount)(); balances[msg.sender] -= _amount; }. The corrective version applies the pattern: require(balances[msg.sender] >= _amount); balances[msg.sender] -= _amount; (bool success, ) = msg.sender.call{value: _amount}(""); require(success, "Transfer failed");. This ensures state is finalized before any external interaction, eliminating the vulnerability.

historical-examples
CASE STUDIES

Historical Examples & Impact

The reentrancy attack is not a theoretical vulnerability; it has been exploited in several high-profile incidents, resulting in significant financial losses and shaping smart contract security practices.

01

The DAO Hack (2016)

The most famous reentrancy attack, which resulted in the theft of 3.6 million ETH (worth ~$50M at the time). The attacker exploited a recursive call vulnerability in the DAO's splitDAO function to repeatedly drain funds before the contract's internal balance was updated. This event directly led to the Ethereum hard fork that created Ethereum (ETH) and Ethereum Classic (ETC).

3.6M ETH
Funds Drained
02

Lendf.Me Hack (2020)

A cross-chain reentrancy attack on the DeFi lending protocol. The attacker used a malicious ERC-777 token on Ethereum to exploit the balanceOf check in the protocol's logic on the Ionic Network. This demonstrated that reentrancy could propagate across interconnected smart contracts and blockchain bridges, leading to a loss of nearly $25 million.

$25M
Approx. Loss
03

Uniswap/Lendf.Me (2020)

A cross-protocol reentrancy attack where the same ERC-777 token exploit was used to manipulate prices on Uniswap to borrow excessive funds from Lendf.Me. This highlighted the systemic risk in the DeFi composability model, where a vulnerability in one protocol (or token standard) can be leveraged to attack another.

04

The "Checks-Effects-Interactions" Pattern

The primary defensive coding pattern developed in response to reentrancy attacks. It mandates a strict order of operations:

  • Checks: Validate all conditions (e.g., balances, permissions).
  • Effects: Update all internal state variables (e.g., deduct balances).
  • Interactions: Perform external calls to other contracts or addresses last. This ensures state is finalized before any external interaction that could trigger a reentrant call.
05

Reentrancy Guards

A mechanical mitigation using a boolean state variable (a "mutex") that locks a function during execution. The most common implementation is OpenZeppelin's ReentrancyGuard contract, which provides nonReentrant and reentrantGuard modifiers. When applied to a function, it prevents any reentrant calls for the duration of that function's execution, providing a robust safety net.

06

Impact on Smart Contract Standards

Reentrancy attacks fundamentally altered token and contract design. The ERC-20 standard became the dominant token standard partly due to its simpler, less callback-prone design compared to ERC-777. Newer standards like ERC-1155 and proposals for ERC-4337 (Account Abstraction) incorporate reentrancy protection considerations from the outset, making security a first-class design constraint.

prevention-patterns
REENTRANCY ATTACK

Prevention Patterns & Best Practices

A reentrancy attack is a critical vulnerability where a malicious contract recursively calls back into a vulnerable function before its initial execution completes, allowing the attacker to drain funds. The following patterns are the primary technical defenses against this exploit.

01

Checks-Effects-Interactions Pattern

The Checks-Effects-Interactions (CEI) pattern is the foundational defense, mandating a strict order of operations within a function.

  • Checks: Validate all conditions (e.g., balances, permissions).
  • Effects: Update all internal state variables (e.g., deducting a balance).
  • Interactions: Perform external calls to other contracts or addresses last. This prevents an external contract from reentering and observing an inconsistent state where funds are not yet deducted.
02

Reentrancy Guard Modifier

A reentrancy guard is a function modifier that uses a boolean lock (nonReentrant) to prevent recursive calls.

  • When a function is called, the lock is set to true.
  • Any reentrant call will fail a require check that the lock is false.
  • The lock is reset to false only after the function completes. This is a robust, generalized solution and is implemented in libraries like OpenZeppelin's ReentrancyGuard.
03

Pull Over Push Payments

The Pull over Push pattern shifts the responsibility for transferring value from the contract to the recipient, eliminating reentrancy risk in the core logic.

  • Instead of the contract actively "pushing" funds to users (e.g., address.send()), it records an obligation in a mapping (e.g., pendingWithdrawals[user] += amount).
  • Users must call a separate withdraw() function to "pull" their funds. This isolates the state-changing logic from the external transfer.
04

Gas Limit Considerations

Using low-level call for transfers introduces reentrancy risk, as it forwards all remaining gas. Safer alternatives impose strict gas limits.

  • transfer and send: Limit forwarded gas to 2300 units, which is only enough for logging, preventing complex reentrant logic. However, they are being phased out due to gas cost variability.
  • Using call with gas limits: Explicitly cap gas for the external call (e.g., {gas: 10000}) to restrict what a reentering contract can do, though this is less secure than CEI or a guard.
05

State Variable Deductions Before Calls

A specific application of CEI is to always deduct balances or update critical state before any external interaction.

  • Vulnerable Code: balances[msg.sender] -= amount; (bool success, ) = msg.sender.call{value: amount}("");
  • Secure Code: uint amountToSend = balances[msg.sender]; balances[msg.sender] = 0; (bool success, ) = msg.sender.call{value: amountToSend}(""); This "zero-out" pattern ensures subsequent reentrant calls find the attacker's balance already updated.
CLASSIFICATION

Types of Reentrancy Attacks

A comparison of the primary reentrancy attack patterns based on their execution method and target.

Attack TypeMechanismPrimary TargetClassic ExamplePrevention Complexity

Single-Function Reentrancy

Reenters the same vulnerable function before its state updates complete.

Balance/State variables

The DAO Hack (2016)

Low

Cross-Function Reentrancy

Reenters a different function that shares state with the vulnerable function.

Interdependent state variables

Cross-contract token transfer

Medium

Cross-Contract Reentrancy

Exploits state shared across multiple contracts via external calls.

Protocol-level shared state

Lending protocol collateral logic

High

Read-Only Reentrancy

A view function is called during reentry, reading inconsistent intermediate state.

Oracle price feeds, view functions

Price manipulation during flash loan

Very High

Deferred Reentrancy

Triggers a state-changing callback later, not in the same transaction.

Events, withdrawal patterns

Callback via selfdestruct or time-lock

High

security-considerations
REENTRANCY ATTACK

Security Considerations for Developers

Reentrancy is a critical vulnerability where an external contract can re-enter a vulnerable function before its initial execution completes, often leading to fund theft.

01

The Core Mechanism

A reentrancy attack exploits the sequence of state changes in a smart contract. The classic pattern involves:

  • An attacker's malicious contract calls a vulnerable function (e.g., withdraw()).
  • The vulnerable function sends Ether (or tokens) to the attacker's contract before updating its internal balance state.
  • The attacker's contract has a receive() or fallback() function that re-enters the vulnerable function, exploiting the outdated balance check to drain funds in a loop.
02

The DAO Hack (2016)

The most famous reentrancy attack resulted in the theft of 3.6 million ETH (worth ~$50M at the time) from The DAO, leading to the Ethereum hard fork. The vulnerability was in a splitDAO function that sent ETH before zeroing the user's balance, allowing the attacker's callback to recursively drain funds. This event is a foundational case study in smart contract security.

03

Checks-Effects-Interactions Pattern

The primary defense against reentrancy is strictly following the Checks-Effects-Interactions pattern:

  1. Checks: Validate all conditions and inputs (e.g., require(balances[msg.sender] >= amount)).
  2. Effects: Update all internal state variables before any external calls (e.g., balances[msg.sender] -= amount).
  3. Interactions: Perform external calls to other contracts or addresses last (e.g., msg.sender.call{value: amount}("")). This order prevents state from being stale during a reentrant call.
05

Cross-Function & Cross-Contract Reentrancy

Reentrancy isn't limited to a single function. Cross-function reentrancy occurs when an attacker re-enters a different function that shares state with the vulnerable one. Cross-contract reentrancy involves state shared across multiple contracts (e.g., a vault and a rewards contract). Defending against these requires careful audit of all state dependencies and applying guards or the Checks-Effects-Interactions pattern consistently across the system.

06

Testing & Formal Verification

Proactive measures are essential:

  • Fuzzing Tools: Use frameworks like Echidna or Foundry's fuzzer to automatically generate inputs that attempt reentrant calls.
  • Static Analysis: Tools like Slither can detect common reentrancy patterns by analyzing contract bytecode.
  • Formal Verification: For high-value systems, use tools like Certora Prover to mathematically prove the absence of reentrancy vulnerabilities under specified invariants.
DEBUNKING MYTHS

Common Misconceptions About Reentrancy

Reentrancy attacks are a foundational concept in smart contract security, yet several persistent myths can lead to dangerous oversights. This section clarifies the most common misunderstandings about the nature, prevention, and detection of reentrancy vulnerabilities.

No, reentrancy is a vulnerability that can be exploited whenever a contract makes an external call to an untrusted contract before resolving its own internal state. While the classic attack involves a .call{value: ...}() to transfer Ether, any external call—such as a token transfer via ERC-20's transferFrom, a call to another contract's function, or even a delegatecall—can provide the re-entry point. The core issue is the state violation; the attacker's fallback function re-enters the vulnerable function while the original contract's critical state (like a user's balance) is still outdated.

REENTRANCY ATTACK

Frequently Asked Questions

Reentrancy attacks are a critical vulnerability in smart contracts where malicious code repeatedly re-enters a function before its initial execution completes, often to drain funds. These questions address its mechanics, prevention, and historical impact.

A reentrancy attack is a smart contract vulnerability where an external malicious contract exploits a state inconsistency by recursively calling back into a vulnerable function before its initial execution finishes. The classic pattern involves a contract that sends funds before updating its internal balance state. An attacker's fallback function or receive function repeatedly calls the vulnerable withdrawal function, draining funds in a single transaction because the contract's state (e.g., the attacker's recorded balance) is not updated until after the recursive calls complete. This violates the checks-effects-interactions pattern.

ENQUIRY

Get In Touch
today.

Our experts will offer a free quote and a 30min call to discuss your project.

NDA Protected
24h Response
Directly to Engineering Team
10+
Protocols Shipped
$20M+
TVL Overall
NDA Protected direct pipeline
Reentrancy Attack: Definition & Prevention in Smart Contracts | ChainScore Glossary