The ETH drip mechanism aims to distribute a fixed amount (sepEthAmountToDrip) to first-time claimers while enforcing a daily cap (dailySepEthCap) via dailyDrips. For qualifying claims (!hasClaimedEth[faucetClaimer] && !sepEthDripsPaused), the logic checks the day (currentDay > lastDripDay) to reset dailyDrips = 0 if a new day has started, then verifies if dailyDrips + sepEthAmountToDrip <= dailySepEthCap before incrementing dailyDrips and transferring ETH.
However, in the else block (non-qualifying claims), dailyDrips = 0 unconditionally resets the counter. An attacker can use a non-first-time address to trigger this reset, zeroing dailyDrips without consuming cap. A subsequent first-time claim then sees dailyDrips = 0, passing the cap check and receiving ETH, repeating the cycle to exceed the daily limit arbitrarily. This abuses the lazy reset design, turning a safety mechanism into an exploitation vector.
Likelihood:
High: Requires only a non-first-time address (easy to create) and a first-time address; no cooldown bypass needed as spammer and exploiter can alternate.
Attack can be automated with multiple accounts, exploiting the reset without consuming cap.
Impact:
High: Enables draining of all contract ETH, halting the faucet indefinitely and denying service to legitimate testnet users needing gas funds.
Economic loss: Unlimited drips could exhaust funding (e.g., 1 ETH cap bypassed for 100+ drips), with no on-chain alerts beyond skipped events.
The following Foundry test demonstrates the vulnerability: A non-first-time claim resets dailyDrips = 0 in the else block, allowing a subsequent first-time claim to receive ETH as if starting fresh. Repeating this cycle exceeds the daily cap, confirming infinite drip abuse.
Add the following to the RaiseBoxFaucetTest.t.sol test:
Setup: Funds the contract and performs an initial first-time claim with user1 to set dailyDrips to 0.005 ETH, verifying the baseline.
Abuse Preparation: Manipulates storage to mark user2 as non-first-time (hasClaimedEth[user2] = true), confirmed via getter.
Cycle 1: User2's claim enters the else block, resetting dailyDrips = 0. User3 (first-time) then claims, passing the cap check (0 + 0.005 <= cap) and receiving ETH, with dailyDrips back to 0.005 ETH.
Cycle 2: Repeats with user4 (spam reset) and user5 (exploit claim), confirming reset and fresh drip.
Cycle 3: Final cycle with user6 (reset) and user7 (exploit), logging and asserting the pattern.
Result: Each cycle bypasses the cap via reset, enabling multiple drips (total > cap). The test passes, proving the vulnerability allows infinite abuse within the same "day."
Remove the erroneous reset from the else block, ensuring dailyDrips = 0 only occurs in the daily rollover check within the if block. This prevents non-qualifying claims from manipulating the cap.
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.