Snowman Merkle Airdrop

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

Missing access control allows arbitrary NFT minting

[H-03] Missing Access Control Allows Arbitrary Snowman NFT Minting

Description

The Snowman::mintSnowman() function is externally callable with no access control, allowing anyone to mint unlimited NFTs. This bypasses the protocol’s intended eligibility requirements and breaks the airdrop mechanism.

function mintSnowman(address receiver, uint256 amount) external { // <@ absence of access control modifier
// @> No checks for who can call this function
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}

Risk

Likelihood:

  • This will occur any time a user discovers the function and calls it, since there is no restriction. No preconditions or prerequisites are needed — only a contract interaction.

  • Any automated system, bot, or attacker can mass-call this function to mint large quantities of NFTs, damaging trust in the collection and making cleanup very difficult.

Impact:

  • Any user can mint unlimited NFTs.

  • Undermines the reward mechanism tied to Snow token holding.

  • Ruins scarcity and value.

Proof of Concept

This test demonstrates how an arbitrary user can mint NFTs at will:

function testCanMintUnlimitedNfts() public {
address attacker = makeAddr("attacker");
vm.prank(attacker);
nft.mintSnowman(attacker, 1000);
console2.log(" attacker's current balance is: ", nft.balanceOf(attacker));
}

Recommended Mitigation

Restrict the mintSnowman() function using access control, and implement a supply cap to prevent infinite minting

// >>> ERROR
...
+ error S__MaxSupplyReached();
+ uint256 public constant MAX_SUPPLY = 10_000;
...
function mintSnowman(address receiver, uint256 amount) external {
if (msg.sender != address(i_airdrop)) revert S__Unauthorized(); // <@ Access control
+
+ if (s_TokenCounter + amount > MAX_SUPPLY) revert S__MaxSupplyReached(); // <@ Cap check
+
+ 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.