Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Missing Input Validation for amount parmeter in `mintSnowman` function enable DoS attacks, supply manipulation, and gas exhaustion

Missing Input Validation for amount parmeter in mintSnowman function enable DoS attacks, supply mainpulation, and gas exhaustion

Description

The Snowman::mintSnowman function has no limits on the amount parameter, allowing users to potentially mint an unlimited number of NFTs in a single transaction.

The follow block of code is responsible for the issue.

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

Risk

Likelihood:

  • Authorized minters (including the airdrop contract) can pass arbitrarily large amounts to the function

  • Malicious or compromised authorized addresses will attempt to mint excessive quantities

  • Users will discover the lack of limits through trial and error or code analysis

  • Gas-based attacks become more likely as the protocol gains popularity and higher transaction volumes

Impact:

  • DoS attacks: Transactions with extremely large amounts can consume excessive gas and potentially fail.

  • Supplay manipulation: Unlimited minting can drastically inflate the NFT supply

  • Gas exhaustion: Large amounts can cause transactions to run out of gas

Proof of Concept

function testUnlimitedAmountExploit() public {
console2.log("=== Testing Unlimited Amount Exploit ===");
vm.startPrank(attacker);
uint256 gasStart = gasleft();
nft.mintSnowman(attacker, 10000);
uint256 gasUsed = gasStart - gasleft();
console2.log("Attacker minted 10000 NFTs in single transaction");
console2.log("Attacker's balance:", nft.balanceOf(attacker));
console2.log("Gas used:", gasUsed);
vm.stopPrank();
}

Recommended Mitigation

contract Snowman is ERC721, Ownable {
+ uint256 public constant MAX_MINT_PER_TX = 1000;
+ uint256 public constant MAX_TOTAL_SUPPLY = 1000000;
... ...
function mintSnowman(address receiver, uint256 amount) {
+ require(amount > 0, "Amount must be greater than 0");
+ require(amount <= MAX_MINT_PER_TX, "Amount exceeds max per transaction");
+ require(s_TokenCounter + amount <= MAX_TOTAL_SUPPLY, "Would exceed max supply");
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
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.