Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
Submission Details
Impact: high
Likelihood: high

Zero-Amount Drip Denial-of-Service via Owner-Controlled Drip Parameters

Author Revealed upon completion

Root + Impact

Description

  • The faucet should always dispense a strictly positive amount of tokens and ETH per claim; users should never be able to trigger a claim that emits Claimed(user, 0) or SepEthDripped(user, 0).

  • The owner can accidentally or maliciously set faucetDrip or sepEthAmountToDrip to zero (or sub-wei values).
    A user can still call claimFaucetTokens(), pay gas, emit events with amount = 0, and increment dailyClaimCount/totalClaimed, wasting storage and polluting the event log.
    At scale this becomes a zero-cost DoS: bots can fill the daily quota with empty claims, denying real users both tokens and ETH for the rest of the day.

// @> No minimum-value check on drip parameters
uint256 public faucetDrip; // can be set to 0
uint256 public sepEthAmountToDrip; // can be set to 0
// @> Claim still proceeds even when drip == 0
_transfer(address(this), faucetClaimer, faucetDrip); // amount may be 0

Risk

Likelihood:

  • Reason 1: Owner function adjustFaucetDrip/sepEth has no require(newAmount > 0), so mis-configuration or fat-finger is one tx away.

  • Reason 2: Once faucetDrip == 0, any bot can cheaply loop 100×, fill dailyClaimCount == dailyClaimLimit for ~2 M gas, blocking legitimate users for 24 h.

Impact:

  • Impact 1: Permanent DoS for the calendar day—real users revert on DailyClaimLimitReached.

  • Impact 2: Storage bloat (dailyClaimCount, lastClaimTime, totalClaimed maps) and event-log spam force archive-node growth and degrade UX.

Proof of Concept

contract ZeroDripBot {
RaiseBoxFaucet public faucet;
constructor(RaiseBoxFaucet _faucet) { faucet = _faucet; }
function lock() external {
// assume owner mistakenly set faucetDrip = 0
for (uint i = 0; i < faucet.dailyClaimLimit(); ++i) {
// each iteration costs < 25 k gas but increments dailyClaimCount
faucet.claimFaucetTokens();
}
}
}

Recommended Mitigation

function adjustFaucetDrip(uint256 newAmount) external onlyOwner {
+ require(newAmount > 0, "RaiseBoxFaucet: drip must be positive");
faucetDrip = newAmount;
}
function adjustSepEthDrip(uint256 newAmount) external onlyOwner {
+ require(newAmount > 0, "RaiseBoxFaucet: sep-eth drip must be positive");
sepEthAmountToDrip = newAmount;
}

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.