Normal Behavior: The burnFaucetTokens() function should allow the owner to burn a specific amount of tokens from the faucet contract's balance. For example, if the contract holds 1,000,000 tokens and the owner calls burnFaucetTokens(50000), exactly 50,000 tokens should be burned and removed from circulation, leaving 950,000 tokens in the contract.
Actual Issue: The function transfers the entire contract balance to the owner first, then only burns the specified amountToBurn. This means the owner receives (totalBalance - amountToBurn) tokens instead of burning them, effectively stealing tokens from the faucet that were meant to be destroyed.
https://github.com/CodeHawks-Contests/2025-10-raisebox-faucet/blob/main/src/RaiseBoxFaucet.sol#L127-L135
Likelihood:
This occurs every time the owner calls burnFaucetTokens() with any amount less than the total contract balance
The owner will naturally call this function when the faucet accumulates excess tokens or when reducing supply is needed
No special conditions required - the bug triggers on normal function execution
Impact:
Token Supply Manipulation: Owner can drain all faucet tokens while appearing to "burn" them, breaking the tokenomics
Faucet Becomes Non-Functional: After a single burn call, the contract has 0 tokens left, preventing all future claims until the owner mints/refills
Trust Violation: Undermines trust in the faucet system, as the total supply can be covertly siphoned to the owner, potentially leading to premature token shortages for legitimate users and violating the "cannot claim faucet tokens" owner restriction.
Accounting Fraud: External observers see burn events but miss the hidden transfer, believing more tokens were destroyed than actually were
The PoC shows that when the owner attempts to burn only 1,000 tokens from a faucet holding 1,000,000,000 tokens, the function mistakenly transfers the entire 1,000,000,000 token balance to the owner but only burns the requested 1,000 tokens, leaving the owner with 999,999,000 stolen tokens. This completely empties the faucet contract (final balance = 0) while the owner illegitimately receives 999,999,000 tokens that should have remained in the faucet for user claims.
To mitigate this, transfer exactly amountToBurn to owner then burn (if intended to burn via owner). If the design requires owner to hold the tokens before burning, transfer only amountToBurn to msg.sender then burn from owner:
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.