Summary
The DAO was an audacious 2016 experiment: a leaderless venture fund living entirely as a smart contract on Ethereum, which raised about $150 million in ether, then roughly 14% of all the ETH in existence. On 17 June 2016 an attacker exploited a reentrancy bug in its withdrawal logic to siphon out about 3.6 million ETH, a third of the fund. The theft forced an existential choice on Ethereum itself: let it stand on the principle that "code is law," or rewrite history to undo it. The community chose to undo it with a hard fork, and the minority who refused kept the original chain alive as Ethereum Classic. It is the foundational smart-contract hack, and the moment a blockchain had to decide whether its own rules were absolute.
How it happened
The DAO let any holder who disagreed with the group split off and withdraw their share of the ether, through a function called splitDAO. The flaw in it is now the most famous bug in crypto: a reentrancy error. The function sent the ether out to the caller before it updated that caller's balance to zero.
The attacker exploited the gap. Their receiving contract had a fallback function that, the instant it received ether from splitDAO, immediately called splitDAO again, re-entering the function before the first call had finished and before the balance had been decremented. So the contract paid out the same balance over and over inside one nested loop, draining far more ether than the attacker was ever owed. About 3.6 million ETH flowed out. What let the bug slip past auditors is that it lived in the interaction of two functions that were each safe on their own: the withdrawal helper was fine in isolation, and splitDAO was fine without it, but together they were lethal, which is exactly why reentrancy is so insidious to review. It is the textbook demonstration of why a contract must follow "checks-effects-interactions", update its own state before making any external call.
The hard fork and the Ethereum Classic split
The drained ether landed in a "child DAO" subject to a 28-day withdrawal delay, which bought the community time to react, and two things happened in that window. A volunteer "Robin Hood Group" used the very same reentrancy bug defensively, draining most of the remaining funds into a protected contract before the attacker could reach them. And the developers first tried a gentler fix, a soft fork to freeze the stolen ether, then abandoned it when Cornell researchers showed it would open a denial-of-service hole. That left a stark choice on a blockchain barely a year old. A smart contract is supposed to be immutable, and Ethereum's founding ideal was that "code is law", whatever the code does is final. But letting the theft stand would gut a large fraction of the young ecosystem. After fierce debate, the community executed a contentious hard fork at block 1,920,000 on 20 July 2016 that effectively rewound the theft and returned the funds. Roughly 85% of the network's mining power followed the new chain, which is the Ethereum we know today. A principled minority refused, arguing that reversing a valid execution betrayed the entire point of an immutable ledger, and kept mining the original chain, which lives on as Ethereum Classic. The split is permanent.
Why The DAO still matters
The DAO matters twice over. As security, it is the original reentrancy catastrophe, and despite being the most studied bug class in the space, reentrancy still drains protocols years later (it returned, through a compiler quirk, in the 2023 Curve hack). Checks-effects-interactions, reentrancy guards, and pull-over-push withdrawals are all standard practice because of it. As philosophy, it forced the question of whether a blockchain's immutability is truly absolute, and the answer, a community will override it under enough pressure, is written permanently into the existence of two Ethereums. (A year later, the US SEC ruled that DAO tokens had been unregistered securities, its first such finding for a crypto token.) The lesson for builders is concrete: update state before external calls, guard fund-moving functions, and test for reentrancy on every one, because "immutable" is a promise your governance may someday be asked to break.
How to fix it
- For an active reentrancy drain there is little to do on-chain except pause the contract if it can be paused; The DAO bought time only because of a 28-day withdrawal delay.
- Replace the contract with a fixed version that follows checks-effects-interactions and adds a reentrancy guard; deployed contracts cannot be edited, so the old one must be retired.
- In the extreme, a chain-level hard fork can reverse the theft, as Ethereum did, but it is socially divisive and splits the community; treat it as a last resort, never a plan.
How to avoid it
- Follow checks-effects-interactions: update balances and totalSupply before any external call.
- Use a reentrancy guard (mutex) on functions that make external calls.
- Prefer pull-over-push withdrawals and minimize ether transfers inside state transitions.
- Limit gas forwarded on external calls or use transfer-style patterns where appropriate.
- Add reentrancy-focused invariant and property tests for every fund-moving function.
References
- https://blog.ethereum.org/2016/07/20/hard-fork-completed
- https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/
- https://www.gemini.com/cryptopedia/the-dao-hack-makerdao
- https://www.coindesk.com/markets/2016/06/21/ethereum-developers-launch-white-hat-counter-attack-on-the-dao
- https://blog.chain.link/reentrancy-attacks-and-the-dao-hack/
Related vulnerabilities
All Web3 →- CRITICALWEB3-PENPIE-2024
On September 3, 2024, Penpie, a yield protocol built on Pendle, was drained of about $27.3 million (11,113.6 ETH in wstETH, sUSDe, egETH and rswETH) across Ethereum and Arbitrum. The root cause was a cross-function reentrancy enabled by permissionless market registration: registerPenpiePool trusted any market from Pendle's PendleMarketFactoryV3 without validating the Standardized Yield (SY) token, so the attacker registered a fake market whose SY was their own contract. PendleStakingBaseUpg.batchHarvestMarketRewards (and its internal _harvestBatchMarketRewards) snapshotted reward-token balances before and after calling the market's redeemRewards, but lacked a nonReentrant guard. The malicious SY's claimRewards callback re-entered PendleStakingBaseUpg.depositMarket with flash-loaned Pendle LP tokens mid-accounting, so the deposit was misattributed as harvested rewards, inflating the attacker's reward balance. Although depositMarket itself carried a nonReentrant modifier, the two functions did not share a lock, so the unguarded harvest path let the attacker re-enter the guarded deposit path and claim the inflated rewards via MasterPenpie.multiclaim.
- CRITICALWEB3-CURVE-VYPER-2023
On 30 July 2023, several Curve Finance pools were drained of about $70 million, and the bug was not in Curve's code at all. It was in the compiler. Specific versions of Vyper, the programming language many Ethereum contracts are written in, generated a broken reentrancy guard, so the protection developers thought they had was silently not working. It is the rare and unsettling case of a reentrancy attack reaching contracts whose authors had correctly added the guard, because the tool that built them betrayed them. It put the spotlight on the compiler and the build pipeline as part of a smart contract's trust boundary.
- CRITICALWEB3-CONIC-2023
On 21 July 2023 Conic Finance's ETH Omnipool on Ethereum lost roughly 1,700 ETH, about $3.6 million, to a read-only reentrancy attack. The attacker flash-loaned around $134 million, deposited into the Curve rETH pool, then called Curve's remove_liquidity(), which sends ETH to the recipient before the pool's totalSupply and balances are finalized, triggering the attacker contract's fallback during an inconsistent intermediate state. Inside that callback the attacker re-entered ConicEthPool.withdraw(), causing Conic's Curve LP oracle to value the LP token from Curve's virtual price and totalSupply while the pool was mid-operation, returning an inflated price. Conic's reentrancy guard was bypassed because its _isETH check assumed Curve v2 ETH pools list the native ETH placeholder address (0xEeee...EEeE) as a coin, whereas they actually use the WETH address, so the guard never fired. The inflated valuation let the attacker mint excess cncETH and withdraw more than deposited.
- CRITICALWEB3-EULER-2023
On 13 March 2023 the Ethereum lending protocol Euler Finance was drained of about $197 million, the biggest DeFi hack of the year. The attacker did not steal a key or break any cryptography. They borrowed a fortune with a flash loan, used a single missing safety check in Euler's code to deliberately push their own position into bad debt, and then exploited Euler's own liquidation rules to be paid far more than they were owed. In a now-familiar twist, the attacker, identifying only as "Jacob," gave more than all of it back over the following weeks. It is a clean lesson in DeFi's defining risk: composable money where one unchecked code path can be turned into a money pump.
- CRITICALWEB3-RARI-FEI-2022
On 30 April 2022 the Rari Capital / Fei Protocol Fuse lending pools on Ethereum lost approximately $80 million (about $79.7 million across ETH, FEI, DAI, LUSD and USDC). Fuse pools were a fork of Compound's CToken, but the CEther contract sent ETH using low-level call.value() instead of Compound's gas-capped transfer(), forwarding all remaining gas to the recipient's fallback. The borrow() function called doTransferOut(), which performed that call.value() ETH transfer to the borrower before the borrow and collateral accounting was finalized, violating checks-effects-interactions. The attacker's fallback re-entered the Comptroller's exitMarket() while the deposited collateral was still counted as backing the loan, freeing the collateral while keeping the borrowed ETH; the Comptroller's reentrancy guard did not cover exitMarket on the affected pools. Funded by Balancer flash loans, this cross-contract reentrancy drained seven pools.
- CRITICALWEB3-BEANSTALK-2022
On April 17, 2022, the Beanstalk stablecoin protocol was drained of about $182 million in a governance attack amplified by a flash loan, netting the attacker roughly $80 million after repaying the loan. The attacker borrowed about $1 billion across Aave and other venues (350M DAI, 500M USDC, 150M USDT plus BEAN and LUSD), deposited it into Curve to mint roughly 795M BEAN3CRV-f and 59M BEANLUSD-f LP tokens, and supplied them to Beanstalk's Silo to instantly hold a supermajority (over 78%, above the two-thirds threshold) of STALK governance power. Beanstalk's emergencyCommit path let a proposal pass once 24 hours had elapsed and a two-thirds vote existed; the attacker had pre-submitted a malicious BIP (BIP-18) whose init contract transferred the protocol's funds, then executed emergencyCommit in a single transaction. The core flaw was that voting power could be acquired flash-loan-instantly with no time-lock against single-block voting. Funds were laundered through Tornado Cash and never recovered; the attacker remains anonymous.