Normal behavior: claimFaucetTokens()
should allow a user to claim the configured single faucet token drip and (for first-time claimers) a single Sepolia ETH drip, subject to the 3-day cooldown and daily caps.
Observed issue: An attacker can reenter claimFaucetTokens()
during the external call{value: ...}
and cause the contract to perform the token transfer multiple times inside a single transaction. As implemented, hasClaimedEth
is set before the external ETH transfer so the ETH bonus is only paid once, but lastClaimTime
, dailyClaimCount
and token transfer occur after the external call — allowing repeated token transfers while cooldown/daily counters are not yet updated. Result: attacker obtains multiple token drips in one transaction (e.g. 2× tokens for attack(2)
) while receiving only 1× ETH.
Likelihood:
The vulnerable pattern (external call before all state updates) is reachable in normal execution by any user calling claimFaucetTokens()
.
A malicious contract can trigger reentrancy via its receive()
/fallback()
while the faucet performs the external ETH transfer, reproducing the condition reliably on a local fork or testnet.
Impact:
Attacker can receive multiple token drips per single transaction, bypassing the 3-day cooldown and per-day claim limits — enabling rapid extraction/abuse of faucet token supply.
This can lead to depletion of the faucet token balance, allowing attackers to front-run or grief future legitimate users and undermine the intended rate-limiting.
Even though ETH bonus is not doubled in current code, draining tokens may still have material consequences for downstream systems that rely on faucet tokens (testnet bootstrapping, gating access, or marketplace simulations).
Add import to RaiseBoxFaucet.t.sol
:
AttackerContract.sol
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.
The contest is complete and the rewards are being distributed.