Skip to content

Push-Payment DoS (Loop of External Transfers)

SAFE-0124 Denial of Service Checked automatically by the scanner
1

What goes wrong

The contract pays out to many addresses inside a single loop. One recipient that reverts (a contract with a reverting receive, or an out-of-gas fallback) makes the whole loop revert, so nobody can be paid — a griefing or fund-freeze vector.

2

The vulnerable pattern

proof of concept — how it is exploited
// for (uint i; i<winners.length; i++) winners[i].transfer(prize);
// attacker registers a contract whose receive() { revert(); }
// now every payout tx reverts -> prizes are frozen for everyone.
3

How to fix it

the pattern that is safe
// pull over push: let each user withdraw their own share
mapping(address => uint256) public owed;
function withdraw() external {
    uint256 a = owed[msg.sender]; owed[msg.sender] = 0;
    (bool ok,) = msg.sender.call{value: a}(""); require(ok);
}
King of the Ether. Use the withdrawal (pull) pattern.
Check your own contract for this

The SaferICO scanner runs 201 detectors over your Solidity source, SAFE-0124 among them. Paste an address or the source itself — a small per-scan fee, shown before you sign, or unlimited on any plan.

Run the scanner See how it is attacked Read the docs