Attacker calls a vulnerable function repeatedly within itself, exploiting incomplete state updates to drain funds
Game
Try to find what's wrong with the withdraw function, how would you turn this code secure?
// SPDX-License-Identifier: MIT// Open me in VSCode and really think before opening the hints!// Add @audit tags wherever suspicious// Go to the solidity docs to complete missing knowledge of what's happening here// Solve by drafting a fix!pragmasolidity ^0.8.0;contract ReentrancyGame {mapping(address=>uint256) public balances;functiondeposit() publicpayable { balances[msg.sender] += msg.value; }functionwithdraw() public {require(balances[msg.sender] >0,"Insufficient balance"); (bool success, ) = msg.sender.call{value: balances[msg.sender]}("");require(success,"Transfer failed"); balances[msg.sender] =0; }}
When reviewing smart contract code, always check if any state changes (e.g., updating balances or other internal values) happen after an external call, especially when using .call
Notice the order of operations in withdraw - does the balance update happen before or after the funds are sent?
When msg.sender is a smart contract, it can have a receive or fallback function that gets triggered automatically when it receives Ether.
If this function calls withdraw again (before the balance is updated), it can re-enter the vulnerable function.
functionwithdraw() public {uint256 amount = balances[msg.sender];require(amount >0,"Insufficient balance");// Fix: set balance to zero before transferring balances[msg.sender] =0; (bool success, ) = msg.sender.call{value: amount}("");require(success,"Transfer failed");}