Fabian Owuor
The DAO was a decentralized venture capital fund built on the Ethereum blockchain. It aimed to allow investors to fund projects without traditional intermediaries. Participants could use smart contracts to pool Ether (ETH) and vote on proposals, with profits distributed back to token holders.
The DAO raised $150 million worth of ETH in one of the first large-scale Initial Coin Offerings (ICOs), representing a significant portion of all ETH in circulation.
The DAO smart contract contained a critical vulnerability within its code, specifically in the split
function. This function allowed investors to withdraw their funds and create a new DAO if they disagreed with decisions. However, a flaw in its implementation enabled an attacker to recursively call the function and extract more funds than they were entitled to.
The issue stemmed from the order of operations in the code:
Balance Reduction: The smart contract was supposed to reduce the sender's balance after transferring funds.
Transfer Functionality: However, the code executed the fund transfer before updating the balance.
This allowed the attacker to:
Call the split
function to withdraw funds.
Before the contract could update their balance, invoke the function recursively.
Repeat this loop until a significant amount of ETH was drained.
Below is a simplified pseudocode representation of the split function:
solidityCopy codefunction splitDAO(address recipient, uint256 amount) public {
// Step 1: Transfer ETH to the user or child DAO
recipient.call.value(amount)(); // Potential reentrancy vulnerability
// Step 2: Update the user's balance
balances[msg.sender] -= amount;
// Step 3: Update the total DAO balance
totalDAOFunds -= amount;
}function splitDAO(address recipient, uint256 amount) public {
The issue arises because the call.value
function in Step 1 transfers ETH and allows arbitrary external code execution (e.g., the recipient\u2019s fallback function). This external code could recursively call splitDAO
again before the user\u2019s balance is updated in Step 2.
Initiation: The attacker called the split function, requesting a withdrawal of funds.
Reentrancy: When the contract executed the call.value
to transfer ETH, it triggered the attacker\u2019s fallback function.
Recursive Calls: The fallback function called the split function again before the balance update, causing the contract to transfer funds repeatedly.
Drain Funds: This recursive loop continued until a significant amount of ETH was drained into a child DAO controlled by the attacker.
The reentrancy vulnerability in the DAO split function could have been mitigated through best practices, such as:
Update State Before Transfers: Modify internal balances and records before transferring funds:
solidityCopy codebalances[msg.sender] -= amount;
totalDAOFunds -= amount;
recipient.call.value(amount)();
Use the Checks-Effects-Interactions Pattern: Always perform checks and state updates before external interactions.
Reentrancy Guards: Use a mutex (boolean lock) to prevent reentrant calls:
solidityCopy codebool locked = false;
function splitDAO(address recipient, uint256 amount) public {
require(!locked, "Reentrancy detected");
locked = true;
recipient.call.value(amount)();
balances[msg.sender] -= amount;
totalDAOFunds -= amount;
locked = false;
}
Back to the story, on June 17, 2016, a hacker exploited the recursive vulnerability to drain approximately 3.6 million ETH (worth ~$50 million at the time) into a child DAO they controlled. The hack was not an external attack on Ethereum but an abuse of flawed smart contract logic.
Preparation: The attacker identified the vulnerability in the DAO\u2019s code.
Execution of Split: They initiated the split
function, transferring funds to a new DAO.
Recursive Calls: The exploit repeated the split
function call recursively, withdrawing funds in a loop before the balance could be updated.
Funds Secured: The drained ETH was moved into a separate address under the attacker\u2019s control.
The Ethereum community and developers were alerted to the hack within hours. The funds stolen were locked in the attacker\u2019s child DAO, bound by the same smart contract rules. According to those rules, the attacker could not withdraw the funds immediately; a 28-day holding period was enforced for any split.
This delay provided the Ethereum community with a brief window to act.
The DAO hack divided the Ethereum community. There were two main proposed responses:
Do Nothing: Allow the blockchain to run as is, adhering to the principle of immutability. This would let the attacker keep the funds.
Hard Fork: Alter the Ethereum blockchain to return the stolen ETH to investors.
The community chose the latter option. On July 20, 2016, Ethereum implemented a hard fork, which:
Rewound the blockchain to a point before the hack.
Redirected the stolen ETH to a refund smart contract.
This decision led to the creation of two Ethereum chains:
Ethereum (ETH): The chain that implemented the fork.
Ethereum Classic (ETC): The original chain, maintained by those who opposed the fork on ideological grounds.
Code Security: The DAO hack underscored the critical importance of rigorous code audits in smart contracts.
Immutability Debate: The hard fork raised philosophical questions about blockchain governance and immutability.
Birth of Ethereum Classic: The event split the Ethereum community and gave rise to a new cryptocurrency, Ethereum Classic.
Investor Awareness: It highlighted risks in decentralized systems, particularly for early-stage blockchain projects.
The DAO hack remains one of the most significant events in blockchain history. While it showcased the potential of decentralized finance, it also highlighted vulnerabilities and governance challenges. The response\u2014including the hard fork\u2014set a precedent for how the blockchain community addresses crises, balancing technical realities with ideological principles.