The root cause of the vulnerability is a violation of the Checks-Effects-Interactions (CEI) security pattern. The claimFaucetTokens function incorrectly performs an external call (Interaction) before it finalizes the state changes (Effects).
This creates a window where an attacker's contract can receive ETH and immediately call back into the claimFaucetTokens function. Because the state variables like lastClaimTime have not yet been updated, the initial security checks will pass a second time, allowing a double-claim. The direct impacts are a potential theft of faucet tokens and a loss of confidence in the contract's ability to enforce its own rules.
Likelihood:
The reentrancy occurs whenever a first-time claim is made by a malicious smart contract that implements a receive() or fallback() function to re-enter the claimFaucetTokens function.
Impact:
Theft of Faucet Tokens: An attacker can double-claim, or potentially multi-claim, faucet tokens with every transaction, draining the faucet's supply much faster than intended.
Inconsistent State: The contract's internal accounting for cooldowns (lastClaimTime) and daily limits (dailyClaimCount) becomes unreliable and can be bypassed, leading to unfair token distribution.
Explanation
The following code demonstrates a practical exploit of this vulnerability. The scenario unfolds as follows:
A malicious Attacker contract calls claimFaucetTokens().
The RaiseBoxFaucet sends ETH to the Attacker, triggering its receive() payable fallback function.
Within the receive() function, the Attacker immediately calls claimFaucetTokens() again.
Because the lastClaimTime was not updated after the first call, the faucet's security checks pass a second time, and the attacker successfully claims another set of tokens.
Explanation:
To remediate the vulnerability, the function must be refactored to strictly adhere to the Checks-Effects-Interactions pattern. All state-modifying effects must be finalized *before* any interaction with an external contract.
The proposed change reorders the function logic as follows:
Effects First: State variables such as lastClaimTime and dailyClaimCount are updated immediately after the initial security checks.
Interaction Last: The external .call() that sends ETH is moved to the end of the function.
This change ensures that the contract's state is always consistent before it interacts with any outside address. Any re-entrant call will now correctly fail the security checks because the state will have already been updated.
\
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.