Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Lack of Maximum Mint Limit Allows Unlimited NFT Supply in Snowman.sol

Root + Impact

Description

  • The mintSnowman function should mint a controlled number of Snowman NFTs, tied to Snow token staking via the SnowmanAirdrop contract, maintaining a scarce supply to preserve economic value.

  • The function does not enforce a maximum total supply, allowing an unlimited number of NFTs to be minted, which destroys scarcity and undermines the project’s tokenomics.

// Root cause in the codebase with @> marks to highlight the relevant section
function mintSnowman(address receiver, uint256 amount) external {
for (uint256 i = 0; i < amount; i++) {// @> No cap on total mints
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;// @> Increments indefinitely
}
}

Risk

Likelihood:

  • Occurs whenever mintSnowman is called repeatedly, as there’s no supply cap.

  • Exploitable immediately after deployment, especially given the lack of access control and other vulnerabilities (e.g., multiple claims in SnowmanAirdrop.sol)

Impact:

  • Unlimited NFT minting eliminates scarcity, devaluing Snowman NFTs and harming collectors/investors.

  • Breaks the project’s economic model, leading to loss of user trust and potential project failure.

Proof of Concept

Snowman snowman = Snowman(snowmanAddress);
// Attacker or authorized caller (e.g., SnowmanAirdrop) mints excessively
snowman.mintSnowman(attacker, 1000000);// Mints 1 million NFTs// Repeat indefinitely to inflate supply

Recommended Mitigation

+ uint256 constant MAX_SUPPLY = 10000; // Define max supply (e.g., 10,000 NFTs)
- function mintSnowman(address receiver, uint256 amount) external {
+ function mintSnowman(address receiver, uint256 amount) external onlyAirdrop {
+ if (s_TokenCounter + amount > MAX_SUPPLY) revert("Exceeds max supply");
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
Invalidated
Reason: Design choice

Support

FAQs

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