A reentrancy attack exploits a vulnerability in smart contract code where a function makes an external call to another contract before its own state has been fully updated — allowing the called contract (controlled by the attacker) to “re-enter” the original function and repeat the call before the first invocation completes. The most famous reentrancy attack is The DAO hack of June 2016, which drained 3.6 million ETH (~$60 million at the time) and led directly to the Ethereum/Ethereum Classic hard fork.
How It Works
The following sections cover this in detail.
Vulnerable Pattern: Withdraw Function
Consider a simplified vulnerable withdrawal contract:
“`solidity
// VULNERABLE – DO NOT USE
mapping(address => uint) public balances;
function withdraw(uint amount) public {
require(balances[msg.sender] >= amount);
// Step 1: Send ETH to the caller
(bool sent, ) = msg.sender.call{value: amount}(“”);
require(sent);
// Step 2: Update balance AFTER sending (WRONG ORDER)
balances[msg.sender] -= amount;
}
“`
The Attack
- Attacker deposits 1 ETH ?
balances[attacker] = 1 ETH - Attacker calls
withdraw(1 ETH) - Contract checks:
balances[attacker] >= 1 ETH? - Contract sends 1 ETH to attacker…
- ETH transfer to attacker triggers attacker’s
receive()function - Attacker’s
receive()function immediately callswithdraw(1 ETH)again - Contract checks again:
balances[attacker] >= 1 ETH— STILL TRUE (Step 2 hasn’t executed yet!) - Contract sends another 1 ETH…
- This loops until the contract is drained or gas runs out
- Only after the loop resolves does Step 2 execute — too late
The DAO Hack (2016)
The most consequential reentrancy attack in history:
- Target: The DAO — a decentralized venture fund with 11.5 million ETH (~$150M at the time) raised through a crowdsale
- Vulnerability: The DAO’s
splitDAO()function had a reentrancy vulnerability in its withdrawal mechanism - Method: Attacker exploited the split mechanism to repeatedly drain ETH into a “child DAO” before the parent DAO’s balances were updated
- Amount stolen: 3.6 million ETH
- Consequences:
Ethereum community debated “code is law” vs. intervention
Hard fork implemented (July 2016) to return funds to DAO token holders on what became Ethereum (ETH)
Minority who rejected the fork continued on Ethereum Classic (ETC)
The DAO hack is the reason Ethereum Classic exists.
The Fix: Checks-Effects-Interactions Pattern
The correct defense is simple — reorder operations so state is updated before external calls:
“`solidity
// CORRECT: Checks-Effects-Interactions Pattern
function withdraw(uint amount) public {
// CHECK: verify conditions
require(balances[msg.sender] >= amount);
// EFFECT: update state BEFORE sending
balances[msg.sender] -= amount;
// INTERACTION: only now make the external call
(bool sent, ) = msg.sender.call{value: amount}(“”);
require(sent);
}
“`
With this ordering, when the attacker re-enters withdraw, the balance is already zero — the require fails immediately.
Other Defenses
ReentrancyGuard (mutex lock):
OpenZeppelin’s ReentrancyGuard contract adds a mutex that prevents re-entrant calls:
“`solidity
import “@openzeppelin/contracts/security/ReentrancyGuard.sol”;
contract Safe is ReentrancyGuard {
function withdraw(uint amount) public nonReentrant {
// …
}
}
“`
Pull payment pattern:
Instead of pushing ETH to users, let them pull (initiate) their own withdrawals — limits reentrancy attack surface.
Cross-Function and Cross-Contract Reentrancy
More complex variants:
- Cross-function reentrancy: Attacker re-enters a different function in the same contract
- Cross-contract reentrancy: Two contracts share state; attacker exploits reentrancy across both
- Read-only reentrancy: Attacker exploits a contract that reads (not writes) from another contract whose state is temporarily inconsistent during an external call — even read-only functions can be exploited this way
Cross-contract and read-only reentrancy are harder to detect and have caused several post-2020 DeFi exploits.
Common Misconceptions
“Smart contract audits eliminate reentrancy risk”
Audits significantly reduce but don’t eliminate risk — complex reentrancy across multiple contracts can be missed. Cross-contract and read-only reentrancy require careful analysis of all external calls and state access patterns.
“Solidity’s transfer() and send() prevent reentrancy”
transfer() and send() forward only 2300 gas, which is too little for reentrant state changes. However, gas costs are not a reliable security mechanism — gas pricing can change (EIP-1884 changed gas costs of certain opcodes), and call{value:} (needed for flexibility) doesn’t have this gas limit. Best practice is Checks-Effects-Interactions + ReentrancyGuard, not relying on gas limits.
Social Media Sentiment
Reentrancy attacks are foundational smart contract security knowledge. Every Solidity developer is expected to understand the pattern, the DAO hack, and the Checks-Effects-Interactions fix. The topic appears in every serious Solidity course and security guide. DeFi security researchers reference reentrancy in audit reports constantly. The DAO hack remains one of the most discussed events in Ethereum’s history for its technical causes and political consequences (the Ethereum/Ethereum Classic split).
Last updated: 2026-04
Related Terms
Sources
- Luu, L., Chu, D.-H., Olickel, H., Saxena, P., & Hobor, A. (2016). Making Smart Contracts Smarter. ACM CCS.
- Ethereum Foundation. (2016). The DAO Event. Ethereum Blog.
- OpenZeppelin. (2022). Reentrancy After Istanbul. OpenZeppelin Blog.