Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
Submission Details
Impact: high
Likelihood: high

Anyone can mint unlimited number of tokens to any address.

Author Revealed upon completion

Description

The mintSnowman function is declared "external" with no access control whatsoever. Any address can call it to mint as many snowman NFTs as possible to any recipient.

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:

  • High.

    Since the function is declared external, anyone can call it without any prerequisites or on-chain cost beyond gas.

Impact:

  • High

    Unrestricted minting allows complete takeover of the NFT supply. Even legitmate NFTs might become inaccessible if the attacker keeps minting NFTs to recipients (DoS).

Proof of Concept

Append the following code to TestSnowman.t.sol and then run forge test --match-contract TestSnowman
, if all test passed it means that the user bob has minted 31800 tokens.

function testNonOwnerCanExploitUnlimitedMint() public {
vm.prank(bob);
nft.mintSnowman(bob, 31800);
assertEq(nft.balanceOf(bob), 31800);
assertEq(nft.getTokenCounter(), 31800);
}

Recommended Mitigation

Restrict access to `mintSnowman` by adding a modifier that checks if the caller is authorized or not. So only the authorized addresses can call it, otherwise it will revert. The only_Owner modifier has require statement that check if msg.sender is equal to the deployed SnowmanAirdrop contract's address:

modifier only_Owner{
require(msg.sender == airdropContractAddr, "Not Authorized");
_;
}
- function mintSnowman(address receiver, uint256 amount) external {
+ function mintSnowman(address receiver, uint256 amount) external only_Owner {

Support

FAQs

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