Crypto
2 min read

Reentrancy Attack

A smart-contract exploit where a malicious contract repeatedly calls back into a vulnerable function before its state is updated, draining funds. The famous DAO hack of 2016 used this technique.

How reentrancy attacks work

The mechanic:

  1. Vulnerable contract sends ETH or tokens to caller before updating internal state.
  2. Attacker contract receives the funds.
  3. Receiver function calls back into the vulnerable contract.
  4. Vulnerable contract still shows funds available (state not yet updated).
  5. Attacker withdraws again — and again, recursively.
  6. Funds drained before the original transaction completes.

The exploit takes advantage of the order of operations: send funds first, update state later.

The DAO hack

The canonical example (June 2016):

  • The DAO — Ethereum-based investment fund holding $150M in ETH.
  • Reentrancy vulnerability in withdrawal function.
  • Attacker drained ~$50M through repeated reentrant calls.
  • Ethereum hard-forked to reverse the theft, creating Ethereum (with reversal) and Ethereum Classic (without).

This single hack reshaped Ethereum's history and produced lasting community division about "code is law" vs. interventionist response.

Why reentrancy is preventable

Standard defense — "checks-effects-interactions" pattern:

  1. Checks — verify conditions first.
  2. Effects — update state next.
  3. Interactions — external calls last.

By updating state before sending funds, the contract is in correct state if a reentrant call happens. The vulnerable code does the opposite.

Other defenses:

  • Reentrancy guards — modifier preventing function from being called recursively.
  • Pull-over-push pattern — let users withdraw rather than pushing payments.

Notable reentrancy exploits

Beyond the DAO:

  • Lendf.Me (April 2020) — $25M drained.
  • Uniswap V1 ERC-777 vulnerability — $25M+ in various incidents.
  • Cream Finance (2021) — $130M lost partly through reentrancy-related dynamics.
  • Curve Finance (July 2023) — $70M+ via Vyper compiler bug enabling reentrancy.
  • Various smaller incidents.

Reentrancy remains one of the most common smart-contract vulnerabilities despite well-known defenses.

Why mistakes persist

Several reasons:

  • Subtle interactions. Reentrancy can occur through indirect call chains.
  • New patterns. Each new programming pattern can introduce new vulnerabilities.
  • Solidity quirks. Specific language features (call vs. transfer; ERC-777 hooks) create attack surfaces.
  • Compiler bugs can introduce reentrancy even in correctly-written code (the Vyper bug was this).
  • Cross-contract interactions — reentrancy can arise from interactions between contracts.

Auditing helps but doesn't eliminate the risk.

Protection mechanisms

Standard defenses:

  • Reentrancy guard modifier. Most production contracts include this. OpenZeppelin's ReentrancyGuard is widely used.
  • Pull-over-push. Users withdraw rather than receive pushed payments.
  • Checks-effects-interactions ordering.
  • Limited gas forwardedtransfer() forwards only 2300 gas, preventing complex reentrant calls (though this is now considered insufficient).
  • Comprehensive auditing.

What developers should know

For Solidity developers:

  • Always use reentrancy guards on functions with external calls.
  • Update state before external interactions.
  • Be aware of cross-contract reentrancy — not just same-contract.
  • Think about ERC-777 hooks when handling tokens.
  • Test extensively — especially edge cases involving callbacks.

For users:

  • Use audited protocols with reentrancy protection.
  • Watch for unaudited or rushed deployments that may have vulnerabilities.
  • Major protocols typically have multiple defense layers.

Reentrancy is one of the oldest and most-studied smart-contract vulnerabilities. Despite well-known defenses, it continues to produce exploits. Whether through subtle interactions, compiler bugs, or developer mistakes, the pattern persists across the ecosystem.