
Reentrancy Attack in Solidity: What It Is, Real Examples, and How to Prevent It (2026)
A reentrancy attack occurs when a malicious smart contract repeatedly calls a vulnerable contract's withdraw function before the balance updates — draining all funds in a loop. It is the most common smart contract vulnerability and caused the $60 million DAO hack in 2016. Reentrancy attacks cost $35.7 million in 2025 alone — including the $62 million Curve Finance exploit, one of the most battle-tested protocols in DeFi. Use the free Blockhertz AI Smart Contract Auditor to check your contracts for reentrancy vulnerabilities in under 60 seconds.
What is a Reentrancy Attack?
A reentrancy attack exploits the order of operations in a smart contract. When a contract sends ETH to an external address before updating its own state, an attacker can use a malicious contract to call back into the vulnerable contract before the state update happens. The result: the balance check passes every time, and the attacker withdraws funds repeatedly until the contract is empty.
Reentrancy is not a new vulnerability — it has been known since 2016. Yet it continues to drain millions every year because developers still make the same fundamental mistake: interacting with external contracts before updating internal state.
How Did the $60 Million DAO Hack Happen?
In June 2016, an attacker exploited a reentrancy vulnerability in The DAO — a decentralized autonomous organization holding $150 million in ETH. The attacker drained $60 million before the team could react. The attack was so significant it led to the Ethereum hard fork that created ETH and ETC — the most controversial event in Ethereum's history and a decision that permanently split the community.
The DAO hack remains the most studied smart contract exploit ever. It directly caused Ethereum to hard fork to recover stolen funds. No other smart contract vulnerability has had deeper consequences for blockchain infrastructure.
The attack sequence:
- Attacker calls withdraw()
- Contract checks balance — passes
- Contract sends ETH to attacker
- Attacker's fallback function calls withdraw() again
- Contract checks balance again — still not updated
- Contract sends ETH again
- Loop repeats until contract is empty
Real World Reentrancy Incidents
| Incident | Year | Loss | Protocol Type |
|---|---|---|---|
| The DAO | 2016 | $60M | Investment DAO |
| Cream Finance | 2021 | $18.8M | Lending protocol |
| Curve Finance | 2023 | $62M | Stablecoin DEX |
| Orion Protocol | 2023 | $3M | DEX aggregator |
| Total losses 2025 | 2025 | $35.7M | Multiple protocols |
The Curve Finance exploit in 2023 is particularly important to understand. Curve is one of the most audited and battle-tested protocols in DeFi — yet a reentrancy vulnerability in a specific version of Vyper (not even in Solidity) allowed attackers to drain $62 million. No contract is immune without proper protection at every layer.
What Does Vulnerable Reentrancy Code Look Like?
// VULNERABLE — do not use
contract VulnerableBank {
mapping(address => uint256) public balances;
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "No balance");
// ❌ Sends ETH BEFORE updating balance
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
// ❌ Balance updated AFTER sending — too late
balances[msg.sender] = 0;
}
}
// ATTACKER CONTRACT
contract Attacker {
VulnerableBank public target;
constructor(address _target) {
target = VulnerableBank(_target);
}
function attack() external payable {
target.deposit{value: msg.value}();
target.withdraw();
}
receive() external payable {
if (address(target).balance >= msg.value) {
target.withdraw();
}
}
}
How Do You Prevent Reentrancy Attacks in Solidity?
Prevent reentrancy using three proven approaches: the Checks-Effects-Interactions pattern, OpenZeppelin ReentrancyGuard, and the Pull Payment pattern. Always update state before making external calls and add the nonReentrant modifier to all functions that send ETH.
According to smart contract security research, reentrancy accounts for approximately 1% of total blockchain losses — but its historical significance is disproportionate. The $60M DAO hack in 2016 triggered the most controversial event in Ethereum history and shaped every security standard that followed. In 2025, $35.7 million was still lost to reentrancy attacks despite the fix being well-known and straightforward to implement.
What is the Checks-Effects-Interactions Pattern?
The Checks-Effects-Interactions (CEI) pattern is the most important rule in Solidity: always update state BEFORE making external calls. First check conditions, then update state variables, then make external calls.
// SECURE — CEI pattern applied
contract SecureBank {
mapping(address => uint256) public balances;
function withdraw() external {
uint256 amount = balances[msg.sender];
// CHECK — verify condition
require(amount > 0, "No balance");
// EFFECT — update state first
balances[msg.sender] = 0;
// INTERACTION — external call last
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
How Does OpenZeppelin ReentrancyGuard Work?
OpenZeppelin's ReentrancyGuard adds a mutex lock that prevents reentrant calls. Add the nonReentrant modifier to any function that sends ETH or calls external contracts — it automatically reverts if the function is called again before completing.
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureBank is ReentrancyGuard {
mapping(address => uint256) public balances;
function withdraw() external nonReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0, "No balance");
balances[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
emit Withdrawal(msg.sender, amount);
}
event Withdrawal(address indexed user, uint256 amount);
}
What is the Pull Payment Pattern in Solidity?
The Pull Payment pattern eliminates push-based ETH transfers entirely. Instead of sending ETH to users, record what they are owed and let them withdraw it themselves. This removes the external call from critical state-changing logic.
contract PullPayment {
mapping(address => uint256) private pendingWithdrawals;
function allowWithdrawal(address recipient, uint256 amount) internal {
pendingWithdrawals[recipient] += amount;
}
function withdraw() external {
uint256 amount = pendingWithdrawals[msg.sender];
require(amount > 0, "Nothing to withdraw");
pendingWithdrawals[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
Reentrancy Attack Checklist
| Check | Status |
|---|---|
| State updated before external calls | ✅ Required |
| ReentrancyGuard on withdraw functions | ✅ Recommended |
| No external calls in loops | ✅ Required |
| Return values from call() checked | ✅ Required |
| Pull payment pattern for ETH distribution | ✅ Recommended |
What is Cross-Function Reentrancy?
Cross-function reentrancy occurs when two functions in the same contract share state and one makes an external call before updating that shared state. An attacker can exploit both functions in a single transaction.
// VULNERABLE — cross-function reentrancy
contract CrossFunctionVuln {
mapping(address => uint256) public balances;
function withdraw() external {
uint256 amount = balances[msg.sender];
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] = 0;
}
function transfer(address to, uint256 amount) external {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
Fix: Apply ReentrancyGuard to all functions that share state, not just withdraw.
What is Read-Only Reentrancy?
Read-only reentrancy is a newer attack vector (2022+) where view functions are exploited during a reentrant call when state is temporarily inconsistent. Price oracle reads stale state, flash loan attacks combine with read-only reentrancy, and multiple DeFi protocols were exploited this way in 2022-2023.
The Curve Finance $62 million exploit in 2023 involved a read-only reentrancy variant. Several protocols that integrated with Curve read its stale pool state during the exploit window and made incorrect decisions as a result — amplifying the total damage beyond the initial attack.
Fix: Add ReentrancyGuard to view functions that read critical state when used as price oracles by other protocols.
How Do You Check Smart Contracts for Reentrancy Vulnerabilities?
The Blockhertz AI Smart Contract Auditor automatically detects reentrancy vulnerabilities in your Solidity, Rust, Move, or Vyper contracts in under 60 seconds.
- Go to blockhertz.com/tools/ai-auditor
- Paste your smart contract
- Click Audit Contract
- Get a full security report with risk score and fix recommendations
Free to start — no signup required: blockhertz.com/tools/ai-auditor
Summary
- Reentrancy = attacker calls back into your contract before state updates
- DAO hack = $60M stolen via reentrancy in 2016 → caused Ethereum hard fork
- Curve Finance = $62M lost in 2023 despite being a battle-tested protocol
- 2025 losses = $35.7M still lost to reentrancy that year
- CEI pattern = always update state before external calls
- ReentrancyGuard = add nonReentrant modifier to all sensitive functions
- Cross-function and read-only reentrancy = newer variants to watch for
References
- Analysis of the DAO Exploit — Hacking Distributed (2016)
- Reentrancy — Consensys Smart Contract Best Practices
- ReentrancyGuard — OpenZeppelin Documentation
- SWC-107: Reentrancy — Smart Contract Weakness Registry
- Smart Contract Security — Ethereum.org
Related Blockhertz Tools
Automatically detect reentrancy and 10+ other vulnerabilities in your smart contracts at blockhertz.com/tools/ai-auditor — free, no signup required.
Related Articles
Blockchain Security Statistics 2026: Smart Contract Hacks, Losses and Trends
$3.4 billion stolen from blockchain projects in 2025. Access control failures cost $953 million. Audited contracts have 98% fewer hacks. Complete blockchain security statistics for 2026 — updated monthly by the Blockhertz team.
Read article →Smart Contract SecurityInteger Overflow in Solidity: What It Is, Real Examples, and How to Prevent It (2026)
Integer Overflow in Solidity: What It Is, Real Examples, and How to Prevent It (2026) An integer overflow vulnerability occurs when arithmetic operations exceed the maximum value a data type can hold...
Read article →Smart Contract SecurityBlockhertz vs Slither: Smart Contract Security Tool Comparison (2026)
Blockhertz AI Auditor and Slither are both free smart contract security tools — but they serve different purposes. This guide compares both to help you choose the rightone for your workflow.
Read article →Resource Hub
Smart Contract Security Hub →
Free AI auditor, vulnerability guides and security research
Explore Blockhertz
Views
52
Read Time
8 min read
Likes
2
Published
Aug 4, 2026
SIGNAL THREAD
NO SIGNALS YET — BE FIRST TO TRANSMIT
Muhammad Asif
Senior Blockchain Developer & Founder, Blockhertz
Blockchain developer and security engineer with 8+ years of experience. Founded Blockhertz in 2018 to build AI-powered tools for Web3 teams — smart contract auditing, architecture generation, gas optimization, and RWA tokenization platforms. Serving clients worldwide.