Reentrancy in withdraw()
SWC-107 · Smart contract agent · Exploitability 9.7
Exploit path
External call to msg.sender executes before the balance is updated, so a malicious receiver can re-enter withdraw() and drain the pool.
Why the fix works
Applies checks-effects-interactions and adds a reentrancy guard. The state update now happens before value leaves the contract.
function withdraw(uint256 amt) external {function withdraw(uint256 amt) external nonReentrant { require(balances[msg.sender] >= amt); balances[msg.sender] -= amt; (bool ok, ) = msg.sender.call{value: amt}(""); require(ok, "transfer failed"); balances[msg.sender] -= amt;}- Exploit no longer reproduces on fork
- Existing test suite passes (212)
- Gas delta +2.1%