Raisebox Faucet

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

# `RaiseBoxFaucet::burnFaucetTokens` transfers more than intended before burning

RaiseBoxFaucet::burnFaucetTokens transfers more than intended before burning

Description

burnFaucetTokens() should allow the owner to burn a specific amount of faucet tokens: transfer that amount to the owner and then call _burn with the same value.

In reality, the function ignores amountToBurn when transferring and moves the entire contract balance (balanceOf(address(this))) to the owner before burning only the requested amount. The difference between the total balance and amountToBurn remains in the owner's wallet unintentionally.

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(amountToBurn <= balanceOf(address(this)), "Faucet Token Balance: Insufficient");
@> _transfer(address(this), msg.sender, balanceOf(address(this)));
_burn(msg.sender, amountToBurn);
}

Risk

Likelihood: Medium

  • Only the owner can call it, but it's common to want to burn a partial amount and each time the function drains the entire faucet to the owner.

  • There are no hidden conditions: balanceOf(address(this)) always sends the full balance, so the error appears on the first partial burn attempt.

Impact: High

  • The faucet is emptied even if you only wanted to destroy part of the tokens, leaving users without rewards.

  • Until the owner manually returns tokens, the contract is halted and onboarding of legitimate users is affected.

Proof of Concept

  1. Prepare the faucet with a balance greater than the amount you want to burn.

  2. As owner, call burnFaucetTokens(amountPartial).

  3. Observe how the owner receives the entire balance minus amountToBurn, while the faucet is left at zero.

  4. Any user trying to claim afterwards will revert due to insufficient balance.

function test_BurnLeavesOwnerWithExcess() public {
uint256 faucetBalanceBefore = raiseBoxFaucet.balanceOf(address(raiseBoxFaucet));
uint256 burnAmount = 1000 ether; // any partial amount
vm.prank(owner);
raiseBoxFaucet.burnFaucetTokens(burnAmount);
assertEq(
raiseBoxFaucet.balanceOf(owner),
faucetBalanceBefore - burnAmount,
"Owner keeps the original balance minus amountToBurn"
);
assertEq(
raiseBoxFaucet.balanceOf(address(raiseBoxFaucet)),
0,
"Faucet is emptied"
);
vm.prank(user1);
vm.expectRevert();
raiseBoxFaucet.claimFaucetTokens();
}

Recommended Mitigation

Update the transfer to use amountToBurn and avoid moving the rest of the balance to the owner.

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(amountToBurn <= balanceOf(address(this)), "Faucet Token Balance: Insufficient");
- _transfer(address(this), msg.sender, balanceOf(address(this)));
+ _transfer(address(this), msg.sender, amountToBurn);
_burn(msg.sender, amountToBurn);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Unnecessary and convoluted logic in burnFaucetTokens

Support

FAQs

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