Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

User can mint unlimited tokens from this function `mintSnowman`

Description

The mintSnowman function allows any user to mint an unlimited number of tokens without enforcing a maximum total supply. This lack of a cap creates a critical vulnerability where users can inflate the total token count arbitrarily, undermining the value, scarcity, and functionality of the token ecosystem.

Without any constraint on s_TokenCounter, malicious or careless users can flood the supply, potentially crashing interfaces, exhausting storage, or rendering the NFT system unusable or economically broken.


Risk

Likelihood:

High — This issue can be easily exploited by any external user without needing special permissions. Exploitation is as simple as calling the mint function with a large amount parameter.

Impact:

  • Token Inflation : The absence of a hard cap allows infinite token minting, defeating any intended scarcity and destroying economic value.

  • Storage and Gas Concerns : A massive number of tokens stored on-chain increases storage and gas costs, possibly leading to out-of-gas failures in future transactions.

  • Reentrancy Risk : The current pattern places _safeMint() before updating s_TokenCounter, increasing the risk window for reentrancy in malicious contracts.


Proof of Concept

This test demonstrates that:

  • The user can mint 1,000 tokens in a single call.

  • No supply cap prevents minting far more.

  • Repeating this call allows infinite minting, which can crash UIs, disrupt tokenomics, and waste storage.

function testUnlimitedMinting() public {
address user = address(0x123);
// Initial token counter should be 0
assertEq(nft.getTokenCounter(), 0);
// User can mint 1000 tokens in one transaction
vm.startPrank(user);
nft.mintSnowman(user, 1000);
vm.stopPrank();
// Verify 1000 tokens were minted
assertEq(nft.getTokenCounter(), 1000);
// Verify user owns all 1000 tokens
for (uint256 i = 0; i < 1000; i++) {
assertEq(nft.ownerOf(i), user);
}
}
}

Recommended Mitigation

  • Global Supply Cap: The use of maxTokenAllowed enforces a hard limit on how many tokens can exist, preserving scarcity and maintaining ecosystem integrity.

  • Fail-Fast on Overflows: The minting function now reverts early if the requested amount would exceed the cap, protecting against inflation or overflow bugs.

  • Scalable Tokenomics: By enforcing this rule from the constructor, different deployments can set different supply limits while maintaining core safety.

+ uint256 private immutable maxTokenAllowed;
constructor(
string memory _SnowmanSvgUri
+ uint256 _maxTokensAllowed;
) ERC721("Snowman Airdrop", "SNOWMAN") Ownable(msg.sender) {
s_TokenCounter = 0; //set max suppply of tokens
s_SnowmanSvgUri = _SnowmanSvgUri;
+ maxTokenAllowrd = _maxTokenAllowed
}
function mintSnowman(address receiver, uint256 amount) external {
+ if (s_TokenCounter + amount > i_MaxSupply) revert SM__NotAllowed();
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unrestricted NFT mint function

The mint function of the Snowman contract is unprotected. Hence, anyone can call it and mint NFTs without necessarily partaking in the airdrop.

Support

FAQs

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