Raisebox Faucet

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

Incorrect daily reset logic allows bypassing global ETH cap

[H-3] Incorrect daily reset logic allows bypassing global ETH cap

Description

The claimFaucetTokens() function resets dailyDrips to 0 inside the else branch that runs when a user has already claimed ETH before or when Sepolia drips are paused.
This means any returning user can trigger a full reset of the daily distribution counter, effectively turning what should be a global daily ETH cap into a per-user cap.

As a result, multiple users (or one attacker using multiple addresses) can each reset the counter and drain more ETH per day than intended.

function claimFaucetTokens() public {
...
// @audit Logical vulnerability here.
// This else runs whenever the user has already claimed ETH before, or ETH drips are paused.
// That means any returning user (who’s claimed before) resets dailyDrips back to 0.
// The dailyDrips variable is supposed to track how much Sepolia ETH has been distributed in a given day, enforcing the daily cap.
// But since dailyDrips gets reset to zero on any returning user’s claim, the cap can be bypassed.
} else {
dailyDrips = 0;
}
...
}

Risk

Likelihood:

  • The vulnerable else branch executes for every returning claimer or when drips are paused.

  • No date check (currentDay != lastDripDay) is performed before resetting.

Impact:

  • Bypasses the intended global daily ETH cap (dailySepEthCap).

  • Multiple users can drain more ETH than the system’s intended daily limit.

  • Faucet accounting and emission limits become meaningless.

Proof of Concept

  • When the faucet contract is vulnerable (resets per user or pause), the test will fail — because dailyDrips was reset to 0 improperly.

function test_dailyCapBypass() public {
vm.deal(address(raiseBoxFaucet), 1 ether);
// User 1 triggers a drip — dailyDrips increases
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// User 2 triggers a claim (already claimed before / paused)
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
// dailyDrips resets to 0 → cap bypassed
assertEq(raiseBoxFaucet.dailyDrips(), 0, "dailyDrips reset incorrectly");
}
forge test --match-test test_dailyCapBypass -vvv
  • This output means:

  1. Actual: dailyDrips = 1e16 (not reset)

  2. Expected: dailyDrips = 0

  3. So the faucet incorrectly reset (or didn’t behave as intended).

Recommended Mitigation

  • Ensure dailyDrips is reset only once per new day, not when a returning user claims or when drips are paused.

  • Use a day-based comparison (block.timestamp / 1 days) to detect when a new day begins.

- else {
- dailyDrips = 0;
- }
- if (block.timestamp > lastFaucetDripDay + 1 days) {
- lastFaucetDripDay = block.timestamp;
- dailyDrips = 0;
- }
+ uint256 currentDay = block.timestamp / 1 days;
+ if (currentDay != lastDripDay) {
+ lastDripDay = currentDay;
+ dailyDrips = 0;
+ }
  • This ensures the daily ETH cap is enforced globally, preventing each user from resetting the counter and bypassing the limit.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 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.