Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Incorrect dailyDrips reset allows bypass of daily Sepolia ETH cap

Root + Impact

A logic bug in claimFaucetTokens() resets the dailyDrips counter via an else { dailyDrips = 0; } block when a caller already received the Sepolia ETH drip (or when drips are paused). This lets an attacker with any previously dripped address repeatedly reset the daily counter and cause the contract to pay out ETH beyond the intended dailySepEthCap.

Description

Inside claimFaucetTokens() the contract attempts to drip Sepolia ETH only to first-time claimants and enforce a daily cap via dailyDrips and lastDripDay. However, an else block unconditionally sets dailyDrips = 0 when the condition (!hasClaimedEth[claimer] && !sepEthDripsPaused) is false - i.e., when the caller has already received ETH or drips are paused.

Because token-only claims by already-dripped addresses execute that else, any such call will reset the daily counter even within the same day. An attacker can:

  • Use or create an address A that has already received a Sepolia ETH drip (hasClaimedEth[A] = true).

  • After legitimate drips have increased dailyDrips, call claimFaucetTokens() from A (token-only claim), which triggers the else and sets dailyDrips = 0.

  • The contract now believes zero ETH has been distributed today and will allow additional first-time claimants to receive ETH up to dailySepEthCap again.

  • Repeat to drain ETH repeatedly past the intended daily limit.

function claimFaucetTokens() public {
//rest of the code
} else {
@> dailyDrips = 0;
}

Risk

Likelihood:

  • The else { dailyDrips = 0; } line resets the daily drip counter in situations where it should not - it is executed when the caller has already claimed ETH. dailyDrips should only be reset on day rollover (i.e., when currentDay > lastDripDay) - not when a caller who previously received ETH calls again.

  • Exploitability: Easy - requires only one address that previously received a drip (which is trivial to obtain). No complicated conditions or off-chain coordination needed.

Impact:

  • Direct financial impact: High - attacker can bypass dailySepEthCap and drain ETH from the faucet beyond expected limits.

  • Severity: High (funds loss/cap bypass).

Proof of Concept

function testDailyDripsBecomeZeroIncorrectly() public {
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
console.log("Daily drips is: ", raiseBoxFaucet.dailyDrips()); //5_000_000_000_000_000
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
console.log("Daily drips is: ", raiseBoxFaucet.dailyDrips());//10_000_000_000_000_000
advanceBlockTime(block.timestamp + 3 days);
vm.prank(user3);
raiseBoxFaucet.claimFaucetTokens();
console.log("Daily drips is: ", raiseBoxFaucet.dailyDrips()); //5_000_000_000_000_000
vm.prank(user1);
// This will incorrectly set the daily drip to 0
raiseBoxFaucet.claimFaucetTokens();
console.log("Daily drips is: ", raiseBoxFaucet.dailyDrips()); //0
vm.prank(user4);
raiseBoxFaucet.claimFaucetTokens();
console.log("Daily drips is: ", raiseBoxFaucet.dailyDrips()); //5_000_000_000_000_000
}

Output:

Ran 1 test for test/RaiseBoxFaucet.t.sol:TestRaiseBoxFaucet
[PASS] testDailyDripsBecomeZeroIncorrectly() (gas: 613053)
Logs:
Daily drips is: 5000000000000000
Daily drips is: 10000000000000000
Daily drips is: 5000000000000000
Daily drips is: 0
Daily drips is: 5000000000000000
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.81ms (245.44µs CPU time)
Ran 1 test suite in 6.82ms (1.81ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

Recommended Mitigation

  • Remove the erroneous else branch so token-only calls won’t zero the counter.

- } else {
- dailyDrips = 0;
- }
+ // Removed: clearing dailyDrips here was incorrect. dailyDrips must only be reset on day rollover.
Updates

Lead Judging Commences

inallhonesty Lead Judge 5 days ago
Submission Judgement Published
Validated
Assigned finding tags:

dailyDrips Reset Bug

Support

FAQs

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