Snowman Merkle Airdrop

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

Lack of access control for `Snowman::mintSnowman()`.

Root + Impact

Snowman::mintSnowman()

Description

The Snowman NFTs can be infinitely minted by anybody without staking the Snow token by calling the Snowman::mintSnowman() function directly because there is no access control in the function, meanwhile, the intended way to mint the Snowman NFT is through the SnowmanAirdrop::claimSnowman() function.

Risk

The NFT is at risk of loosing its value since an infinite amount can be minted for FREE.

Likelihood:

  • High

Impact:

  • High

Proof of Concept

Add the below test to the TestSnowman test suite.
This test generates a random address and calls the mintSnowman function on the nft contract, and asserts that the address indeed receives an NFT.

function test_random_person_can_mint_snowman_nft_without_staking() public {
address randomUser = makeAddr("randomUser");
vm.prank(randomUser);
nft.mintSnowman(randomUser, 1);
assert(nft.ownerOf(0) == randomUser);
assert(nft.balanceOf(randomUser) == 1);
}

Recommended Mitigation

First, we need to pass the address of the airdrop contract into the constructor of the Snowman contract.

contract Snowman is ERC721, Ownable {
+ address private s_snowmanAirdropAddress;
uint256 private s_TokenCounter;
string private s_SnowmanSvgUri;
+ constructor(string memory _SnowmanSvgUri, address _snowmanAirdropAddress) ERC721("Snowman Airdrop", "SNOWMAN") Ownable(msg.sender) {
s_TokenCounter = 0;
s_SnowmanSvgUri = _SnowmanSvgUri;
+ s_snowmanAirdropAddress = _snowmanAirdrop;
}
// Other codes
}

Secondly, in the Snowman::mintSnowman() function, we need to ensure that the msg.sender is the same address as the airdrop address that was passed into the constructor.

function mintSnowman(address receiver, uint256 amount) external {
+ if (msg.sender != s_snowmanAirdropAddress) {
+ revert SM__NotAllowed();
+ }
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 20 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.