What is reentrancy?
A bug in which a contract calls another address before finishing its own bookkeeping, letting the called code call back in and repeat an action.
Not yet verifiedHow we verify
3 min read
In this entry
A bug in which a contract calls another address before finishing its own bookkeeping, letting the called code call back in and repeat an action.
The standard defense is to update state before making external calls and to add a lock that refuses nested entry. Reentrancy remains one of the most common findings in audit reports, which is one reason an audit date and scope matter more than the fact one exists.
The bug is old, well documented, and still shipping. It is not exotic cryptography going wrong; it is an ordering mistake in ordinary code, made possible because on a smart contract platform the address you send funds to can be code that runs immediately and calls you back.
How it works
A vulnerable withdrawal function does three things in the wrong order.
- It checks that your recorded balance is sufficient.
- It sends you the funds.
- It sets your recorded balance to zero.
If the recipient is a contract, step two hands control to that contract's code before step three runs. The attacker's code calls the withdrawal function again. The check in step one passes, because the balance has not been zeroed yet. Funds go out a second time, then a third, until the pool is empty or gas runs out.
Two defenses are standard. The first is ordering: perform every check, then update every piece of state, then make external calls last, so a re-entry finds the books already settled. The second is a mutex, a lock the function sets on entry and refuses to pass while set.
Cross-function and read-only variants exist too, where the re-entry hits a different function or reads a price mid-update. See oracle and flash loan, which frequently appear in the same incidents.
Example
The pattern's most consequential appearance was the 2016 attack on The DAO, which drained a large share of the funds it held and led to the Ethereum hard fork that split the chain into Ethereum and Ethereum Classic (source: the Ethereum Foundation's account of the DAO fork).
The mechanics were exactly the ordering error above. A recursive call re-entered the withdrawal function before the internal balance was reduced, so the same balance was withdrawn repeatedly. Nothing about the cryptography failed. The contract simply did its bookkeeping in the wrong order, and the consequences reshaped the network.
Why it matters when you buy
You will not read contract source before every deposit, but you can check the things that correlate with this class of bug: whether the code is audited, when, by whom, and whether the deployed contract is the audited one. Verifying a token contract covers the lookup, and Buyability and the exchange directory cover the custodial alternative, where the operational risk sits with a company instead.
Related terms
smart contract — where the bug lives; smart contract audit — the usual review, with limits; flash loan — supplies capital for exploits; proxy contract — why audited code may not be running; defi — the domain most exposed; hard fork — the DAO response.
Questions
Is reentrancy still a real risk?
Yes. The defenses are well known and still omitted, and newer variants involving read-only calls and cross-function paths continue to appear in audit findings and incident reports.
Does an audit mean a contract is safe?
No. It means specified code was reviewed on a date under a stated scope. Bugs are missed, scope excludes things, and upgradeable deployments can replace the reviewed code entirely.
How does this affect me if I only use an exchange?
Directly, very little. Custodial accounts move balances in a company's database rather than through contracts you call. You are exposed to that company instead, which is a different risk rather than no risk.