All Guides
SecuritySecurityReentrancy

How Reentrancy Attacks Work

A technical walkthrough of reentrancy attacks — from The DAO hack to modern variants — with code examples and prevention patterns.

Updated February 25, 2026 8 min read

Reentrancy is the single most well-known smart contract vulnerability. Despite being identified in 2016, it continues to cause losses. Understanding exactly how it works is essential for every blockchain developer.

The Core Mechanism

A reentrancy attack exploits the order of operations in a Solidity function: if a function makes an external call (like transferring ETH) before updating its internal state, the external call can trigger a callback into the original function before the state update happens. The attacker's function re-enters the vulnerable function in a previous state — allowing them to repeat the operation (e.g., withdraw the same funds) multiple times.

A Simple Vulnerable Example

Consider a contract with a withdraw() function that: (1) checks the caller's balance, (2) transfers ETH to the caller, then (3) updates the balance to zero. An attacker deploys a contract that, in its receive() function, calls withdraw() again. The attacker's withdraw() call triggers their receive(), which triggers another withdraw() before the original call can update the balance — recursively draining the contract.

The DAO Hack (2016)

The DAO's splitDAO function used a similar pattern. A recursive call through a callback allowed attackers to repeatedly call the split function without updating balances. The attack drained 3.6M ETH ($60M at the time) from The DAO. The response — Ethereum's hard fork to reverse the transactions — remains the most controversial event in Ethereum's history.

Cross-Function Reentrancy

Single-function reentrancy is well-understood. More subtle is cross-function reentrancy: function A calls an external contract, which calls function B in the original contract, which reads state that A hasn't updated yet. This can be missed by developers focused only on single-function patterns. The fix is the same — ReentrancyGuard or careful state management — but the analysis requires considering all pairs of functions.

Read-Only Reentrancy

An emerging pattern: contract A is protected against write reentrancy, but an attacker reenters during a view function call that's being used by contract B as a price oracle. Contract A's storage is in a transitional state, so the view returns wrong data, allowing B to be exploited. This pattern affected multiple Curve-reliant protocols in 2023.

Prevention Patterns

Checks-Effects-Interactions (CEI): always update state before making external calls. OpenZeppelin's ReentrancyGuard: a modifier using a mutex flag to prevent reentrant calls. Favor pull-over-push payment patterns: instead of the contract sending ETH to users, let users withdraw themselves. Never use transfer() or send() — use call() with explicit checks, and apply CEI.

In an Audit

Auditors specifically look for: any external call before a state update, any function that sends ETH or calls unknown external contracts, callbacks in ERC-721 safeTransfer and ERC-1155 transfer hooks, and functions that can be called in any order. The presence of ReentrancyGuard doesn't eliminate the analysis — it needs to be applied correctly.

Ready to build your Web3 project?

Tell us about your project and get a precise quote.

Get a Project Quote