Reentrancy is a critical smart contract vulnerability where a contract calls an external contract before updating its own state, allowing the external contract to recursively call back and drain funds. This flaw has resulted in over $100M in cumulative losses across DeFi, including The DAO ($60M, 2016), Lendf.me ($25M, 2020), and Cream Finance ($37.5M, 2021). Firepan's HOUND AI detects reentrancy vulnerabilities automatically during development and post-deployment monitoring, covering continuous analysis across the full contract lifecycle.
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);
}
}
}
| Protocol | Date | Loss | Root Cause | |----------|------|------|-----------| | The DAO | 2016-06 | $60M | Recursive call in splitDAO() before state update | | Lendf.me | 2020-02 | $25M | ERC777 token hook reentrancy in lending contract | | Cream Finance | 2021-02 | $37.5M | Reentrancy in crToken transfer logic | | Curve (Vyper) | 2023-07 | $70M+ | Vyper compiler reentrancy lock bug in stable pools | | bZx Flash Loan | 2020-02 | $954K | Reentrancy combined with flash loan manipulation |
Manual detection requires analyzing call sequences:
.call{}, .send(), .transfer(), interface calls)Look for these red flags:
Firepan's HOUND AI combines static and dynamic analysis:
Firepan's HOUND AI engine catches single-function, cross-function, and read-only reentrancy across all monitored contracts.
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: Which protocols have been exploited via reentrancy attack?
A: The DAO (2016, $60M), Lendf.me (2020, $25M), and Cream Finance (2021, $37.5M) suffered major reentrancy exploits. The DAO attack was the most infamous, leading to the Ethereum hard fork. Reentrancy remains a critical vulnerability vector across DeFi.
Q: How does Firepan detect reentrancy attack?
A: Firepan uses HOUND AI to map control flow, detect Checks-Effects-Interactions violations, perform symbolic execution, and run Echidna fuzz tests. Slither and Mythril provide static analysis, while deployment monitoring detects suspicious recursive call patterns in real-time.
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 OpenZeppelin's ReentrancyGuard, implement pull-over-push patterns, and avoid state-dependent fallback functions. Scoped analysis with Firepan prevents these issues during development.
Reentrancy remains blockchain's most devastating vulnerability class, responsible for over $100M in losses. The fix is straightforward: always update state before external calls. Firepan's HOUND AI detects CEI violations across all monitored contracts, blocking reentrancy exploits before they reach mainnet.
Start securing your smart contracts at https://app.firepan.com/
Firepan
12,453 contracts secured. 2,851 vulnerabilities blocked. 236 exploits prevented. Run a free surface scan — results in minutes, no credit card required.
Run Free Scan →