Skip to content
Last updated: February 06, 2026

SCWE-046: Reentrancy Attacks

Stable Version v1.0

This content is in the version-(v1.0) 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.

Remediation

  • 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.8.0;

contract Vulnerable {
    mapping(address => uint) public balances;

    function withdraw(uint _amount) public {
        require(balances[msg.sender] >= _amount);
        (bool success, ) = msg.sender.call{value: _amount}(""); // Vulnerable: external call before state update (reentrancy)
        require(success, "Transfer failed");
        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"; // OZ 5.x: utils/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;
    }
}