mirror of
https://github.com/autistic-symposium/blockchains-security-toolkit.git
synced 2025-05-13 04:02:16 -04:00
.. | ||
README.md | ||
reentrancy.sol |
reentrancy attacks
tl; dr
- when a contract calls an external function, that external function may itself call the calling function.
- a reentrancy attack may occur when:
- a function makes an external call to a untrusted contract
- the unstrusted contract makes a recursive callback to a vulnerable contract function to steal funds
- to prevent this attack, a contract can implement a lock in storage that prevents re-entrant calls.
- bt3gl's diagram:
example
for example, suppose this method:
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
(bool success, ) = msg.sender.call.value(amountToWithdraw)("");
requires(success);
userBalances[msg.sender] = 0;
}
and this exploit:
function() public payable {
if(msg.sender == address(vulnContract)) {
vulnContract.withdrawBalance();
}
}
how to fix?
option 1: Adding a mutex locking:
modifier noReentrant() {
require(!locked, "nooooope");
locked = true;
_;
locked = false;
}
so
function withdrawBalance() public noReentrant {
...
}
option 2: CEI (checks effects interaction) pattern
function withdrawBalance() public {
uint amountToWithdraw = userBalances[msg.sender];
userBalances[msg.sender] = 0; // update state first
(bool success, ) = msg.sender.call.value(amountToWithdraw)("");
requires(success);
}