What is a reentrancy attack?
A reentrancy attack happens when a smart contract calls another contract before it has finished updating its own state, and the other contract calls back in to repeat an action, such as a withdrawal, against the stale state. It is the oldest bug in Ethereum and still lands, because modern versions hide in chains of cross-contract calls and read-only view functions.
The basic pattern
- A contract sends funds or makes an external call to a user-controlled address.
- Before the contract updates its records, the receiving contract calls back in.
- The original contract still sees the old balance and pays out again.
- The loop repeats until the funds are gone.
The variants
- Single-function. The same function is re-entered.
- Cross-function. A callback enters a different function that shares state.
- Cross-contract. State split across several contracts is inconsistent during a call.
- Read-only. A view function returns stale data mid-call, and a different protocol relies on it.
- Token callbacks. ERC-777 hooks and ERC-721 or ERC-1155 receiver callbacks create call-outs that developers forget about.
Prevention
- Checks-effects-interactions. Validate, update state, and only then make external calls.
- Reentrancy guards on functions that make external calls, including guards that also protect view functions others depend on.
- Pull over push. Let users withdraw, rather than sending funds in loops.
- Review every external call, including token transfers, as a possible re-entry point.
HYDN’s audits trace every external call for reentrancy. Read our longer article on reentrancy attacks.
Frequently asked questions
Does a reentrancy guard fix everything?
A guard stops re-entry into guarded functions of the same contract. It does not stop cross-contract reentrancy or read-only reentrancy, where another protocol reads your state mid-update. Following checks-effects-interactions is still essential.
What is read-only reentrancy?
An attack where a view function, such as a price or share value, returns a stale value during a callback, and another protocol that trusts that value is exploited. Your contract loses nothing directly. Your integrators do.
Published Updated
