Raisebox Faucet

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

[H-2] Transfer Contract Balance To Owner Before Burn Makes Owner Can Siphon Majority of Tokens

[H-2] Transfer Contract Balance To Owner Before Burn Makes Owner Can Siphon Majority of Tokens

Description

  • Normal behavior: burnFaucetTokens should destroy tokens that the faucet contract holds, reducing the contract's token balance and the total supply by the requested amount. The function name and behavior must match: a "burn" operation should not act as a withdraw to the owner.

  • Specific issue: the current implementation transfers the contract's entire token balance to the owner and then calls _burn on the owner for only amountToBurn. As implemented, the owner receives nearly all of the contract tokens while only amountToBurn is actually removed from total supply. This effectively converts a burn function into a privileged withdrawal allowing the owner to siphon the faucet balance.

// Root cause in the codebase with @> marks to highlight the relevant section
function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(
amountToBurn <= balanceOf(address(this)),
"Faucet Token Balance: Insufficient"
);
// transfer faucet balance to owner first before burning
// ensures owner has a balance before _burn (owner only function) can be called successfully
> _transfer(address(this), msg.sender, balanceOf(address(this)));
> _burn(msg.sender, amountToBurn);
}

Risk

Likelihood:High

  • Owner calls burnFaucetTokens while the contract holds any positive token balance — this code path always performs the transfer-to-owner step before burning and therefore will execute the problematic transfer during normal owner operation.

  • Teams deploy or use the contract under the expectation that burnFaucetTokens destroys contract-held tokens — this assumption causes the function to be called in production environments where the unintended transfer will occur during normal maintenance or audits.

Impact:High

  • Direct asset exfiltration: the owner can obtain nearly the entire faucet token balance (contract balance minus the small burned amount), causing immediate financial loss and destruction of trust.

  • Monitoring and accounting blindspots: automated monitors or auditors that only check totalSupply changes will observe the burned amount but may miss that the larger transfer moved tokens to the owner, complicating incident detection and response.

Proof of Concept

// Conceptual PoC scenario:
// - contract holds 1_000_000 tokens at address(this)
// - owner calls burnFaucetTokens(100)
//
// With current implementation:
// 1) _transfer(address(this), owner, 1_000_000);
// 2) _burn(owner, 100);
//
// Result:
// - owner balance increases by 1_000_000 then decreases by 100 => net +999_900 tokens
// - totalSupply decreases by 100
// - contract balance becomes 0
//
// Observed effect: owner gained 999,900 tokens; only 100 tokens were actually burned.

Recommended Mitigation

function burnFaucetTokens(uint256 amountToBurn) public onlyOwner {
require(
amountToBurn <= balanceOf(address(this)),
"Faucet Token Balance: Insufficient"
);
// transfer faucet balance to owner first before burning
// ensures owner has a balance before _burn (owner only function) can be called successfully
- _transfer(address(this), msg.sender, balanceOf(address(this)));
-
- _burn(msg.sender, amountToBurn);
+ // Burn directly from the contract's balance to avoid transferring tokens to owner.
+ _burn(address(this), 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.