Raisebox Faucet

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

Burn Function Transfers All Tokens to Owner Instead of Burning Specified Amount

Description

The burnFaucetTokens() function is intended to burn a specified amount of tokens from the faucet. The function should transfer only the amountToBurn to the owner, then burn that amount.

The function transfers the entire faucet balance to the owner but only burns the specified amountToBurn. This allows the owner to drain the faucet supply while only burning a fraction, keeping the rest.

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(
amountToBurn <= balanceOf(address(this)),
"Faucet Token Balance: Insufficient"
);
// transfer faucet balance to owner first before burning
_transfer(address(this), msg.sender, balanceOf(address(this))); // @> BUG: Transfers ALL tokens
_burn(msg.sender, amountToBurn); // @> Only burns amountToBurn
}

Risk

Likelihood: High

  • Owner can call this function at any time

  • The bug executes on every call to burnFaucetTokens()

  • No special conditions required

Impact: High

  • Owner can drain entire faucet supply by burning only 1 token

  • Example: Faucet has 1,000,000 tokens → owner calls burnFaucetTokens(100,000) → owner receives 1,000,000 tokens, only 100,000 burned → owner keeps 900,000 tokens

  • Breaks faucet economics - tokens meant for users go to owner

  • Defeats purpose of the faucet contract

  • Complete loss of user trust if exploited

Proof of Concept

function testBurnTransfersAllButBurnsPartial() public {
uint256 faucetBalance = raiseBoxFaucet.getFaucetTotalSupply();
uint256 amountToBurn = 100_000 * 10 ** 18;
console.log("Initial faucet balance:", faucetBalance);
console.log("Amount to burn:", amountToBurn);
uint256 ownerBalanceBefore = raiseBoxFaucet.balanceOf(owner);
// Owner calls burn with 100,000 tokens
vm.prank(owner);
raiseBoxFaucet.burnFaucetTokens(amountToBurn);
uint256 ownerBalanceAfter = raiseBoxFaucet.balanceOf(owner);
uint256 faucetBalanceAfter = raiseBoxFaucet.getFaucetTotalSupply();
// Owner received ALL tokens, not just amountToBurn
assertEq(
ownerBalanceAfter - ownerBalanceBefore,
faucetBalance - amountToBurn
);
assertEq(faucetBalanceAfter, 0, "Faucet drained completely");
console.log("Owner received:", ownerBalanceAfter - ownerBalanceBefore);
console.log("Expected to burn:", amountToBurn);
console.log(
"Owner kept:",
(ownerBalanceAfter - ownerBalanceBefore) - amountToBurn
);
}

Output:

Initial faucet balance: 1,000,000,000 tokens
Amount to burn: 100,000 tokens
Owner received: 999,900,000 tokens
Expected to burn: 100,000 tokens
Owner kept: 999,800,000 tokens (99.98% of supply!)

Recommended Mitigation

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 4 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.