The Contract resets dailyDrips = 0 in the else block of the ETH drip logic:
Every time a user who has already claimed ETH calls claimFaucetTokens(), the contract resets dailyDrips to 0.
This resets the daily ETH drip counter, effectively bypassing the dailySepEthCap.
Attacker claims tokens once → receives ETH, hasClaimedEth\[attacker] = true, dailyDrips = 0.005 ether.
Attacker waits < 24 hours (so lastDripDay is unchanged).
Attacker calls claimFaucetTokens() again (after 3-day cooldown is irrelevant—they can wait or use multiple addresses).
Since hasClaimedEth\[attacker] == true, the else block runs: dailyDrips = 0.
Now, a new victim (or the attacker using a second address) claims for the first time.
The contract checks: dailyDrips (0) + sepEthAmountToDrip <= dailySepEthCap → passes.
Victim gets ETH, dailyDrips is incremented again.
Repeat steps 3–4 indefinitely to drain all ETH in the contract, ignoring the daily cap.
Even worse: If the attacker controls two addresses, they can alternate claims to reset dailyDrips before every first-time claim, making the dailySepEthCap completely ineffective.
The else { dailyDrips = 0; } line assumes that non-first-time claims should reset the ETH drip counter, which is logically incorrect.
The daily ETH cap should only reset once per day (based on lastDripDay), not on every non-ETH claim.
Remove the erroneous dailyDrips = 0 reset in the else block. The dailyDrips counter should only be reset once per day in the time-check block:
Vulnerable Code
Fixed Code
Also: The
dailyClaimCountreset logic useslastFaucetDripDaywith1 days, but the ETH drip uses24 hours— standardize to one unit (e.g., 1 days).
This can be tested through a foundry test.
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.