Raisebox Faucet

First Flight #50
Beginner FriendlySolidity
100 EXP
Submission Details
Impact: medium
Likelihood: high

Owner can mint unlimited tokens without supply cap enforcement

Author Revealed upon completion

Root + Impact

Description


Expected behavior:

The faucet should allow the owner to mint new tokens only when the faucet’s balance runs low — ideally with clear upper limits or supply controls to maintain the integrity of the token’s economics and prevent accidental over-minting.


Actual behavior:

The mintFaucetTokens() function allows the owner to mint an arbitrary number of new tokens to the faucet’s address (address(this)), with no effective supply cap or total supply limit. The only check in place (balanceOf(address(this)) > 1000 * 10 ** 18) does not prevent inflation — it simply reverts if the faucet already has more than 1000 tokens, not if it exceeds a maximum total supply.

As a result, the owner can continuously mint new tokens without bound, undermining token scarcity and creating potential inconsistencies between testnet and mainnet behavior.

// Root cause in the codebase with @> marks to highlight the relevant section
if (balanceOf(address(to)) > 1000 * 10 ** 18) {
@> revert RaiseBoxFaucet_FaucetNotOutOfTokens();
}
_mint(to, amount);

Risk

Likelihood

1.High, since any owner interaction can trigger it, even unintentionally.

2.Low technical barrier: The vulnerability is accessible through a single function call.

Impact:

1.Inflation risk: The faucet owner can mint unlimited tokens.

2.Economic inconsistency: Testnet token behavior won’t match real deployment economics.

3. Trust issue: If adapted to mainnet or reused elsewhere, unrestricted minting could devalue tokens.

Proof of Concept

Explanation

This test shows that the owner can repeatedly call mintFaucetTokens() to create arbitrary amounts of tokens. The balance-based check doesn’t prevent this since it only compares against a static threshold. As a result, the faucet contract can hold billions of tokens, rendering the supply logic meaningless and allowing unbounded inflation.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/RaiseBoxFaucet.sol";
contract UnlimitedMintTest is Test {
RaiseBoxFaucet faucet;
address owner = address(this);
function setUp() public {
faucet = new RaiseBoxFaucet("RaiseBox", "RBT", 1000 ether, 0.005 ether, 1 ether);
}
function test_OwnerCanMintUnlimitedTokens() public {
uint256 initialSupply = faucet.totalSupply();
// Owner repeatedly mints more tokens
faucet.mintFaucetTokens(address(faucet), 1_000_000 ether);
faucet.mintFaucetTokens(address(faucet), 1_000_000 ether);
faucet.mintFaucetTokens(address(faucet), 1_000_000 ether);
uint256 newSupply = faucet.totalSupply();
assertGt(newSupply, initialSupply, "Owner can inflate token supply indefinitely");
}
}

Recommended Mitigation

Explanation:

Introduce a maximum total supply cap and enforce it within the mintFaucetTokens() function.This ensures the total minted tokens never exceed a defined maximum supply, preventing uncontrolled inflation while still allowing the faucet to refill tokens safely as intended.

- remove this code
+ add this code
- if (balanceOf(address(to)) > 1000 * 10 ** 18) {
- revert RaiseBoxFaucet_FaucetNotOutOfTokens();
- }
- _mint(to, amount);
+ uint256 MAX_SUPPLY = 1_000_000_000 * 10 ** 18;
+ if (totalSupply() + amount > MAX_SUPPLY) {
+ revert("RaiseBoxFaucet: Mint exceeds max total supply");
+ }
+ _mint(to, amount);

Support

FAQs

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