The claimFaucetTokens() function should follow the Checks-Effects-Interactions pattern to prevent reentrancy attacks by updating all state variables before making external calls.
The function makes an external ETH transfer call before updating critical state variables like lastClaimTime and dailyClaimCount, allowing malicious contracts to re-enter the function during the ETH transfer and drain both tokens and ETH from the contract.
Likelihood: High
Attacker deploys a malicious contract with a receive() function that calls claimFaucetTokens() again
The external call faucetClaimer.call{value: sepEthAmountToDrip}("") transfers control to the attacker's contract
State variables haven't been updated yet, so all checks pass on the reentrant call
Impact: High
Complete drainage of both ETH and token balances from the faucet contract
Permanent disruption of the faucet mechanism for legitimate users
Attack scenario:
Deploy MaliciousReceiver with faucet address
Call attack() - first claimFaucetTokens() call
When faucet sends ETH, receive() is triggered
receive() calls claimFaucetTokens() again before state is updated
All checks pass again because lastClaimTime and dailyClaimCount unchanged
Process repeats until gas limit or contract drained
Result: Attacker receives multiple token transfers and ETH payments
The mitigation involves implementing the ReentrancyGuard modifier from OpenZeppelin and restructuring the function to follow the Checks-Effects-Interactions pattern. This ensures all state changes occur before any external calls, preventing reentrant attacks.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.