Reentrancy Attack

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

  1. Attacker deposits 1 ETH ? balances[attacker] = 1 ETH
  2. Attacker calls withdraw(1 ETH)
  3. Contract checks: balances[attacker] >= 1 ETH ?
  4. Contract sends 1 ETH to attacker…
  5. ETH transfer to attacker triggers attacker’s receive() function
  6. Attacker’s receive() function immediately calls withdraw(1 ETH) again
  7. Contract checks again: balances[attacker] >= 1 ETHSTILL TRUE (Step 2 hasn’t executed yet!)
  8. Contract sends another 1 ETH…
  9. This loops until the contract is drained or gas runs out
  10. 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.