Raisebox Faucet

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

The daily distribution cap of ETH can be bypassed.Infinite acquisition until funds are exhausted

Author Revealed upon completion

Root + Impact

Description

  • In the claimFaucetTokens() function, a serious logical error was identified: when a user has already claimed ETH (entering the else branch), the contract mistakenly resets dailyDrips to 0 regardless of whether a new day has started. This allows the daily ETH distribution limit to be bypassed.

// Root cause in the codebase with @> marks to highlight the relevant section
// Root cause in the codebase with @> marks to highlight the relevant section
function claimFaucetTokens() external claimCooldownOn nonReentrant {
// ... existing code ...
if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
// ... existing code ...
if (currentDay > lastDripDay) {
lastDripDay = currentDay;
dailyDrips = 0;
// dailyClaimCount = 0;
}
// ... existing code ...
} else {
@> dailyDrips = 0; // Incorrectly resets daily drips even when it's not a new day
}
// ... existing code ...
}

Risk

Likelihood:

  • This issue occurs every time a user claims tokens after their cooldown period has expired, regardless of whether a new day has started

  • Any user with basic understanding of the contract's logic can repeatedly claim ETH beyond the intended daily limit once their cooldown period is over

Impact:

  • The contract's ETH balance can be drained much faster than expected, leading to depletion of funds

  • Undermines the fairness of the faucet distribution mechanism, allowing malicious users to hoard more ETH than legitimate users

Proof of Concept

// Code snippet for vulnerability exploitation test
function testLogicFlawInEthDrip() public {
//Phase 1: The first users 1 and 2 receive (new users, receive ETH)
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
vm.prank(user2);
raiseBoxFaucet.claimFaucetTokens();
//Verify the accumulation of dailyDrips
assertEq(raiseBoxFaucet.dailyDrips(), 0.01 ether, "Daily drips should be 0.01 ether after first two claims");
// Phase 2: Wait for the cooldown period of User 1 (3 days and 1 second). At this point, the daily limit should have automatically been refreshed.
uint256 initialTime = block.timestamp;
vm.warp(initialTime + 3 days + 1);
// Stage 3: Create new users 3 and 4 and claim. DailyDrips should have naturally reset and start accumulating again.
address user3 = makeAddr("user3");
address user4 = makeAddr("user4");
vm.prank(user3);
raiseBoxFaucet.claimFaucetTokens();
vm.prank(user4);
raiseBoxFaucet.claimFaucetTokens();
// Verify that dailyDrips correctly accumulates values
assertEq(raiseBoxFaucet.dailyDrips(), 0.01 ether, "Daily drips should be 0.01 ether after user3 and user4 claims");
// Stage 4: Now User 1 re-applies (having already received ETH, the else branch will be triggered)
vm.prank(user1);
raiseBoxFaucet.claimFaucetTokens();
// Verify that dailyDrips has been mistakenly reset to 0
assertEq(raiseBoxFaucet.dailyDrips(), 0, "Critical: dailyDrips was reset to 0 by user1's second claim, allowing daily ETH limit bypass");
}

Recommended Mitigation

if (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused) {
// ... existing code ...
} else {
- dailyDrips = 0; // Remove this erroneous reset operation
}
Updates

Lead Judging Commences

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