Last updated: March 11, 2025
SCWE-046: Reentrancy Attacks
Stable Version v0.0.1
This content is in the version-(v0.0.1) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).
Send Feedback
Relationships
Description
Reentrancy attacks occur when a contract allows untrusted external calls during execution without properly updating state variables or implementing protections. This enables attackers to repeatedly call functions and manipulate the contract’s state before execution completes. Common issues include:
- Making external calls before updating state variables.
- Lack of mechanisms to prevent repeated or recursive calls.
- Improper handling of external interactions.
- Update state first: Modify critical state variables before any external calls.
- Implement reentrancy guards: Use tools like
nonReentrant
modifiers to block recursive calls.
Examples
Vulnerable Contract Example (Reentrancy)
pragma solidity ^0.4.0;
contract Vulnerable {
mapping(address => uint) public balances;
function withdraw(uint _amount) public {
require(balances[msg.sender] >= _amount);
msg.sender.call.value(_amount)(); // Vulnerable external call
balances[msg.sender] -= _amount;
}
function deposit() public payable {
balances[msg.sender] += msg.value;
}
}
Fixed Contract Example
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract Secure is ReentrancyGuard {
mapping(address => uint) public balances;
function withdraw(uint _amount) public nonReentrant {
require(balances[msg.sender] >= _amount, "Insufficient balance");
balances[msg.sender] -= _amount;
(bool success, ) = msg.sender.call{value: _amount}("");
require(success, "Transfer failed");
}
function deposit() public payable {
balances[msg.sender] += msg.value;
}
}