Snowman Merkle Airdrop

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

Lack of checks could lead to multiple exploits in `mintSnowman`

Description

The mintSnowman function lacks critical validation checks on user inputs, particularly the amount and receiver parameters. This opens the contract to several potential exploits:

  • Gas exhaustion denial-of-service (DoS): A user can attempt to mint an extremely large number of tokens (e.g., 1 million), leading to out-of-gas errors.

  • Zero address minting: Tokens could be minted to the zero address, potentially locking them forever.

  • Unreasonable minting operations: Users can call mintSnowman with amount = 0, wasting gas and cluttering execution flow with no meaningful output.

Risk

Likelihood:

High — Exploiting this vulnerability requires no special permissions or cryptographic attacks. It can be triggered by any user calling mintSnowman with an extremely large or malformed input.

Impact:

Denial of Service (High): Unbounded minting can cause transactions to fail due to out-of-gas errors. This could stall contract functionality and deter legitimate users.

  • Token Supply Manipulation (High): Without an upper limit, malicious users could create vast numbers of tokens, affecting game balance, economics, or platform trust.

  • Operational Inconsistencies (Medium): Minting to the zero address or minting zero tokens leads to state pollution or unintended behavior.


Proof of Concept

This test illustrates:

  • The absence of a cap on the amount input.

  • The vulnerability to gas exhaustion by processing a large loop during minting.

  • The potential for network congestion or failed transactions.

  • No validation of the receiver address or minimum amount.

// This will either:
// 1. Run out of gas and revert
// 2. Take an extremely long time to execute
// 3. Cost an enormous amount of gas
function testGasExhaustion() public {
address user = address(0x123);
uint256 hugeAmount = 1000000;
uint256 startGas = gasleft();
vm.startPrank(user);
nft.mintSnowman(user, hugeAmount); // Attempting to mint 1 million tokens
vm.stopPrank();
uint256 gasUsed = startGas - gasleft();
console2.log("Gas used for minting 1 million tokens:", gasUsed);
console2.log("Tokens actually minted before gas exhaustion:", nft.getTokenCounter());
}

Recommended Mitigation

The proposed changes introduce three critical validation checks:

  1. Address validation: Prevents tokens from being minted to the zero address (address(0)), avoiding loss of assets.

  2. Zero-amount prevention: Stops execution early if the user tries to mint zero tokens, saving gas and maintaining cleaner logic.

  3. Mint cap enforcement: Limits the number of tokens a user can mint in a single transaction (e.g., to 10), mitigating gas exhaustion attacks and maintaining game economy integrity.

function mintSnowman(address receiver, uint256 amount) external {
+ if (receiver == address(0)) revert SM__NotAllowed();
+ if (amount == 0) revert SM__NotAllowed();
+ require(amount <= 10, "Too many mints at once");
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.