claimFaucetTokens()Severity: High
Impact: Allows attacker to drain faucet ETH and tokens via reentrancy.
claimFaucetTokens() makes an external ETH transfer (.call) before updating state such as lastClaimTime, dailyClaimCount, and hasClaimedEth.
Because of this, a malicious contract can re-enter via its receive() function and call claimFaucetTokens() again inside the same transaction, bypassing cooldown and limits.
This breaks CEI (Checks-Effects-Interactions) and no ReentrancyGuard is applied.
Affects all users who can call claimFaucetTokens()
Exploitable every time faucet has ETH
Can drain faucet ETH (0.005 Sepolia ETH per reentry) and duplicate token transfers.
High surface impact as this is the core function of the contract.
Faucet has ETH and tokens funded.
Attacker deploys MaliciousClaimer.
Calls attack().
On first ETH drip, attacker’s receive() re-enters multiple times.
Faucet balance decreases more than intended, attacker gains extra ETH + tokens.
Foundry Test (excerpt):
Observed: Faucet loses ≥ 0.005 * (1+reentries) ETH in one call.
Apply CEI pattern
Do all state updates (lastClaimTime, dailyClaimCount, hasClaimedEth, dailyDrips) before sending ETH.
Add ReentrancyGuard
Import OpenZeppelin’s ReentrancyGuard and mark function nonReentrant.
Remove storage-based faucetClaimer
Use address claimer = msg.sender; locally.
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.