Reentrancy
An external call hands control to the callee before your own state is finished updating.
What it is
On the EVM, calling another address runs that address’s code synchronously — and it may call straight back into you before your original function returns. If your contract writes state after making an external call, the callee can re-enter while your bookkeeping is still stale and act on values you were halfway through changing.
Why it matters
Complete drainage of contract funds. This is the bug class that emptied The DAO, and it still ships regularly because the external call is often three libraries deep: _safeMint calls onERC721Received, ERC-777 tokens call hooks on transfer, and any token you do not control can call you back on an ordinary transfer.
The vulnerable pattern
The balance is cleared after the transfer, so the require passes again on re-entry.
function withdraw() external {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing to withdraw");
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "transfer failed");
balances[msg.sender] = 0; // too late
}The fix, in code
Checks, effects, interactions — plus a guard for defence in depth.
function withdraw() external nonReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0, "nothing to withdraw");
balances[msg.sender] = 0; // effect before interaction
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "transfer failed");
}How to fix it
- Order every function as checks, then effects, then interactions. Update state before calling out, always.
- Add a reentrancy guard to every externally callable function that touches shared state — not only the one that transfers, or cross-function reentrancy reaches the same mapping through a sibling.
- Prefer pull payments: record what each address is owed and let them claim it in a function that does nothing else.
- Audit your view functions too. Read-only reentrancy lets another protocol price against your reserves mid-update.
A full walkthrough of this bug class, including the variants that catch teams who thought they had fixed it, is in the long-form guide.
How it is detected
Every audit on EVM Smart Audit checks for SWC-107 and reports it as passed or flagged in the standards coverage grid — so the report tells you it was checked even when nothing was found. See the detector suite for what else runs alongside it, or the full database for the other 21 checks.
Check your contract for reentrancy
The engine runs this check and 21 others on every audit, and shows what passed as well as what failed.