Reentrancy occurs when an external call can enter contract logic again while important state is still inconsistent. The DAO's recursive-call vulnerability is the canonical example. Firepan can inspect a submitted repository and commit for suspicious call ordering and use best-effort Slither output as corroboration in compatible deep audits; that scoped evidence is not blanket monitoring of deployed contracts.
Reentrancy occurs when a contract makes an external call (typically sending ETH or tokens) before updating its own state variables. If the external contract is malicious, it can call back into the original contract's functions, exploiting the stale state to extract funds repeatedly in a single transaction. This violates the atomicity assumption most developers rely on.
The vulnerability breaks down into three categories:
The core issue stems from violating the Checks-Effects-Interactions (CEI) pattern: state updates must happen before external calls, not after.
The attack sequence follows a predictable pattern:
// VULNERABLE — example only
// Demonstrates: Reentrancy Attack
// Do NOT use in production
pragma solidity ^0.8.0;
contract VulnerableBank {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
// VULNERABLE: State update happens AFTER external call
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
// External call before state update — reentrancy window opens
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
// State update happens too late
balances[msg.sender] -= amount;
}
function getBalance() public view returns (uint256) {
return address(this).balance;
}
}
contract Attacker {
VulnerableBank public target;
uint256 public attackCount = 0;
constructor(address _target) {
target = VulnerableBank(_target);
}
function attack() public payable {
target.deposit{value: msg.value}();
target.withdraw(msg.value);
}
// Fallback function — called when receiving ETH
receive() external payable {
attackCount++;
if (attackCount < 10) {
// Recursively drain the contract
target.withdraw(msg.value);
}
}
}
The Ethereum Foundation described The DAO incident as a recursive-calling vulnerability: the attacker repeatedly entered the split function within the same transaction. That primary account is useful because it identifies the execution pattern without turning a changing asset valuation into a permanent headline statistic.
Manual detection requires analyzing call sequences:
.call{}, .send(), .transfer(), interface calls)Look for these red flags:
Firepan's repository analysis can combine several evidence sources:
No automated result proves the absence of single-function, cross-function, or read-only reentrancy. Reviewers should pair repository analysis with invariant tests, targeted adversarial tests, and operational monitoring appropriate to the deployed protocol.
1. Follow Checks-Effects-Interactions (CEI) Pattern
Update all state variables before making external calls:
// SECURE
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount; // Update state first
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
2. Use Reentrancy Guards
Implement a mutex pattern with OpenZeppelin's ReentrancyGuard:
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureBank is ReentrancyGuard {
function withdraw(uint256 amount) public nonReentrant {
// Function can only be called once per transaction
}
}
3. Pull Over Push Pattern
Let users withdraw funds themselves rather than pushing to them:
// SECURE: Users pull funds
function withdraw() public {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
4. Use Safe Transfer Functions
For ERC20/ERC721, use OpenZeppelin's safe wrappers that handle reentrancy:
IERC20(token).safeTransfer(recipient, amount);
5. Beware of ERC777 and Custom Callbacks
ERC777 tokens invoke a hook during transfer—treat like external calls. Never hold tokens across external calls without guards.
Q: What is reentrancy attack in smart contracts?
A: Reentrancy occurs when a contract calls an external contract before updating its own state, allowing the external contract to recursively call back and exploit the stale state. The classic example is a withdrawal function that sends ETH before decrementing the user's balance.
Q: What is the best-known real reentrancy incident?
A: The DAO incident is the canonical case. The Ethereum Foundation described an attacker recursively entering the split function and collecting ether multiple times in one transaction.
Q: How does Firepan detect reentrancy attack?
A: Firepan uses deterministic patterns and HOUND AI repository analysis to identify suspicious external-call and state-update ordering. Deep audits can use best-effort Slither findings as corroboration and investigate exploitability in context. Teams should still maintain their own invariant tests and deployed monitoring appropriate to the protocol.
Q: Can reentrancy attack be exploited after deployment?
A: Yes. Reentrancy is exploitable post-deployment if the code violates CEI ordering. Attackers watch the mempool for vulnerable function calls and deploy malicious contracts to intercept and exploit them in the same transaction.
Q: How do I prevent reentrancy attack?
A: Follow Checks-Effects-Interactions ordering: update state before external calls. Use a suitable reentrancy guard, consider pull-based payments, and test invariants across callbacks and related entry points. Analysis can find evidence; it does not prevent every issue by itself.
Reentrancy risk is broader than one familiar withdrawal pattern: callbacks can cross functions and can expose inconsistent read-only state. Use CEI where it fits, apply guards carefully, test protocol invariants, and treat automated repository findings as evidence rather than a security guarantee.
Start securing your smart contracts at https://app.firepan.com/
Firepan
Run a free surface scan — results in minutes, no credit card required.
Run Free Scan →