Raisebox Faucet

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

burnFaucetTokens() transfers all faucet balance to owner before burning

Root + Impact

Description

Expected behavior:
Should only burn specified tokens directly.

Actual behavior:

Transfers all faucet tokens to owner, then burns only amountToBurn.

@> _transfer(address(this), msg.sender, balanceOf(address(this)));
@> _burn(msg.sender, amountToBurn);

Risk

Likelihood:

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

  • Reason 2

Impact:

  • Owner unintentionally gains faucet tokens.

Leaves excess tokens unburned or owner-held.

Proof of Concept

Owner calls burnFaucetTokens(1000 ether); receives entire faucet balance.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
PoC: Exploits flawed burnFaucetTokens() logic that transfers full contract balance
to the caller (typically the owner), but only burns the requested amount.
If the faucet has, say, 100,000 tokens, and the caller burns only 1,000,
they still receive the remaining 99,000 tokens.
*/
interface IVulnerableFaucet {
function burnFaucetTokens(uint256 amountToBurn) external;
function balanceOf(address account) external view returns (uint256);
}
contract BurnFaucetTokensPoC {
IVulnerableFaucet public faucet;
constructor(address _faucet) {
faucet = IVulnerableFaucet(_faucet);
}
// Exploit function: only burns small amount, but gets entire balance
function exploit(uint256 amountToBurn) external {
faucet.burnFaucetTokens(amountToBurn);
}
function getBalance() external view returns (uint256) {
return faucet.balanceOf(address(this));
}
}

Recommended Mitigation

Do not transfer the contract’s entire token balance to the caller and then burn only a subset. Burn tokens in-place from the faucet contract address, add sanity checks, and restrict who can call the burn function if appropriate.

This burns amountToBurn directly from the faucet contract and prevents the caller from receiving the remaining balance.

- _transfer(address(this), msg.sender, balanceOf(address(this)));
- _burn(msg.sender, amountToBurn);
+ _burn(address(this), amountToBurn);
Updates

Lead Judging Commences

inallhonesty Lead Judge 9 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.