Root cause. In claimFaucetTokens(), the first-time branch correctly accrues daily ETH usage (dailyDrips += sepEthAmountToDrip) and enforces dailySepEthCap. However, the else block resets dailyDrips back to 0 whenever the caller is not in the first-time path (i.e., hasClaimedEth[claimer] == true) or when ETH drips are paused. As a result, any old claimer can call claimFaucetTokens() and wipe the per-day counter, re-enabling ETH distribution for new users within the same calendar day.
This breaks the intended per-day cap and lets attackers “refill” the daily budget repeatedly, draining the contract ETH much faster than designed.
Impact:
Daily cap bypass: dailySepEthCap becomes meaningless
Rapid depletion: Faucet ETH drained in hours instead of days
Denial of service: Legitimate users face inconsistent availability
Economic damage: Faucet sustainability destroyed
When !hasClaimedEth[claimer] && !sepEthDripsPaused is false, execution jumps to the else block, which sets dailyDrips = 0;. An old claimer (cooldown passed) can thus reset the per-day ETH usage counter at will. New claimers later the same day will again receive ETH, bypassing the daily cap.
This breaks the fundamental daily rate-limiting mechanism of the faucet.
Likelihood:
High - Anyone who has claimed ETH before can trigger the reset after the 3-day cooldown passes. No special setup or conditions required.
Impact:
Daily ETH cap completely bypassed
Fast ETH depletion (hours instead of days)
DoS and instability for legitimate users
Economic damage to faucet operations
The following Foundry test demonstrates the vulnerability. It shows how an old user can reset the dailyDrips counter in the middle of the day, allowing a late new user to receive ETH even after the daily cap was reached. Test execution shows the attack succeeds:
forge test --match-path test/DailyDripsReset.t.sol -vvv
[PASS] test_DailyEthCap_BypassViaElseReset() (gas: 486255)
Suite result: ok. 1 passed; 0 failed; 0 skipped
Result: Daily cap bypassed - 3 ETH drips occurred in one day instead of the intended 2-drip limit.
Explanation:
• Remove the else { dailyDrips = 0; } branch. The daily counter must reset only on day rollover
(currentDay > lastDripDay), which already exists in the first-time branch.
• This preserves the per-day invariant and prevents non-first-time claimers or paused state from zeroing the counter mid-day.
Minimal patch:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.