Snowman Merkle Airdrop

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

Missing Access Control Allows Unlimited Public Minting in Snowman.sol::mintSnowman

Root + Impact

Root: The mintSnowman function lacks any access control modifiers, allowing anyone to mint unlimited Snowman NFTs to any address without restriction or authorization.

Impact: Unrestricted minting completely breaks the intended airdrop mechanism, allowing malicious actors to mint unlimited NFTs, devaluing the collection and undermining the protocol's economic model and scarcity assumptions.

Description

  • Normal Behavior: NFT minting functions should have proper access controls to ensure only authorized contracts or addresses can mint tokens, especially in an airdrop context where scarcity and controlled distribution are important.

  • Specific Issue: Any external caller can invoke mintSnowman() with any receiver address and amount, bypassing the intended airdrop mechanism that should require Snow token staking and Merkle proof validation through the SnowmanAirdrop contract.

Risk

Likelihood: High

  • The function is external and completely unrestricted, making exploitation trivial for any user

  • No authentication or authorization barriers exist to prevent abuse

  • Malicious actors can easily discover and exploit this vulnerability through contract interaction

Impact: High

  • Economic Manipulation: Unlimited minting destroys NFT scarcity and intended tokenomics

  • Airdrop Bypass: Users can obtain NFTs without participating in the intended Snow farming and staking mechanism

  • Protocol Failure: The entire airdrop distribution model becomes meaningless when anyone can mint freely

Proof of Concept

This test demonstrates that any external address can call mintSnowman() without restrictions. The test shows how malicious actors can mint unlimited NFTs to themselves or others, completely bypassing the intended airdrop mechanism. This breaks the protocol's scarcity model and allows anyone to obtain NFTs without staking Snow tokens or providing valid Merkle proofs.


Paste the following into TestSnowMan.t.sol and run with forge test.

function testAnyoneCanMintSnowman() public {
// Malicious actor (not owner, not airdrop contract)
address attacker = makeAddr("attacker");
address victim = makeAddr("victim");
// Attacker can mint unlimited NFTs to themselves
vm.prank(attacker);
nft.mintSnowman(attacker, 100);
// Attacker can also mint NFTs to other addresses without permission
vm.prank(attacker);
nft.mintSnowman(victim, 50);
// Verify the unrestricted minting worked
assert(nft.balanceOf(attacker) == 100);
assert(nft.balanceOf(victim) == 50);
assert(nft.getTokenCounter() == 150);
// Anyone can mint to any address without any restrictions
address anotherAttacker = makeAddr("anotherAttacker");
vm.prank(anotherAttacker);
nft.mintSnowman(anotherAttacker, 1000);
assert(nft.balanceOf(anotherAttacker) == 1000);
}

Recommended Mitigation

Implement proper access control to restrict NFT minting to only the authorized airdrop contract.

+ error SM__NotAllowed();
+ modifier onlyAirdropContract() {
+ if (msg.sender != address(s_airdropContract)) {
+ revert SM__NotAllowed();
+ }
+ _;
+ }
+ address private s_airdropContract;
+ function setAirdropContract(address _airdropContract) external onlyOwner {
+ if (_airdropContract == address(0)) {
+ revert SM__NotAllowed();
+ }
+ s_airdropContract = _airdropContract;
+ }
- function mintSnowman(address receiver, uint256 amount) external {
+ function mintSnowman(address receiver, uint256 amount) external onlyAirdropContract {
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 5 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.