Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

Time-Based Vulnerabilities

Root + Impact

Description

The claimFaucetTokens() function in the RaiseBoxFaucet contract relies on block.timestamp for two critical time-based mechanisms:

  1. Cooldown Enforcement: Ensures users can only claim tokens every 3 days CLAIM_COOLDOWN = 3 days by checking block.timestamp < (lastClaimTime[faucetClaimer] + CLAIM_COOLDOWN).

  2. Daily Reset Logic: Resets the dailyDrips and dailyClaimCount counters to enforce daily limits (dailySepEthCap for ETH drips and dailyClaimLimit for token claims) using two inconsistent methods:

    • ETH drips: block.timestamp / 24 hours to compute currentDay and compare with lastDripDay.

    • Token claims: block.timestamp > lastFaucetDripDay + 1 days to reset dailyClaimCount

Miners can manipulate block.timestamp within a small window (~15 seconds), potentially allowing attackers to bypass cooldowns or reset daily limits prematurely.

// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact:

Miners can adjust block.timestamp by up to ~15 seconds (or more in some networks) to influence the currentDay calculation or cooldown check, potentially:

Allowing a user to claim tokens before the 3-day cooldown expires.

Triggering premature resets of dailyDrips or dailyClaimCount, enabling additional claims within a day.

Proof of Concept

Setup: A user’s lastClaimTime[faucetClaimer] = 100,000, and CLAIM_COOLDOWN = 3 days = 259,200 seconds. A claim is attempted at block.timestamp = 359,100 (just 100 seconds before cooldown expires).

Attack: A colluding miner sets block.timestamp = 359,200 (manipulating +100 seconds).

Result: The check block.timestamp < (lastClaimTime[faucetClaimer] + CLAIM_COOLDOWN) → 359200 < (100000 + 259200) = 359200 becomes false, allowing the claim to succeed early, bypassing the 3-day cooldown.

Recommended Mitigation

Use block numbers instead of block.timestamp for cooldowns, as block numbers are harder to manipulate and provide a more predictable interval

uint256 public constant CLAIM_COOLDOWN_BLOCKS = 3 days / 14; // Approx. 18,514 blocks
mapping(address => uint256) private lastClaimBlock;
function claimFaucetTokens() public {
if (block.number < lastClaimBlock[faucetClaimer] + CLAIM_COOLDOWN_BLOCKS) {
revert RaiseBoxFaucet_ClaimCooldownOn();
}
lastClaimBlock[faucetClaimer] = block.number;
// ... rest of function ...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 13 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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