Unprotected Ether Withdrawal
Detects functions that transfer Ether without verifying the caller's authorization, allowing anyone to drain the contract's ETH balance.
Unprotected Ether Withdrawal
Overview
The unprotected ether withdrawal detector identifies functions that send ETH (via CALL with non-zero value, transfer, or send) without checking that msg.sender matches a privileged address. Any user who discovers such a function can drain the contract’s entire ETH balance.
Sigvex locates CALL instructions with non-zero value operands and checks whether the function contains a CALLER comparison against a stored address before the call.
Why This Is an Issue
This is the simplest form of access control failure: a public function exists that sends ETH to msg.sender or to an address parameter, without any ownership or role check. The Parity multi-sig wallet freeze involved a similar pattern where critical functions lacked access control.
How to Resolve
// Before: Vulnerable — anyone can withdraw
function withdraw() external {
payable(msg.sender).transfer(address(this).balance);
}
// After: Fixed — restrict to owner
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function withdraw() external onlyOwner {
payable(owner).transfer(address(this).balance);
}
Detection Methodology
- ETH transfer detection: Identifies
CALLinstructions where the value parameter is non-zero, plusSELFDESTRUCTwhich forwards remaining balance. - Authorization check search: Looks for
CALLER(msg.sender) loaded and compared (EQ) against a storage value before the transfer. - Destination analysis: Checks whether the ETH destination is
msg.sender(higher risk) or a hardcoded address (lower risk).
Limitations
False positives: Functions protected by access control in a separate modifier or parent contract may be flagged if the check is not inlined. False negatives: Contracts that use assembly-level balance manipulation may be missed.
Related Detectors
- Access Control — detects missing authorization broadly
- Selfdestruct — detects selfdestruct which also transfers ETH