Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

An attacker can mint unlimited SantaTokens and NFTs

Summary

An attacker can mint unlimited NFTs and SantaTokens transfering the NFT to other account.

Vulnerability Details

In SantaList.sol, the collectPresent() is designed for users to claim an NFT if they have a NICE status or an NFT, and additionally, SantaTokens if they possess an EXTRA_NICE status. The issue lies in the present claiming mechanism, where the check to ensure users claim only once is based on balanceOf(msg.sender) > 0.

if (balanceOf(msg.sender) > 0) {
revert SantasList__AlreadyCollected();
}

A vulnerability arises as an attacker can transfer the minted NFT to another account, resetting the balanceOf() to 0. Consequently, the attacker can fraudulently claim the present multiple times, thereby exploiting the protocol. This not only violates the protocol's stipulation that an address should only mint one NFT but also allows the attacker to mint an unlimited number of SantaTokens.

Impact

The attacker can mint an unlimited quantity of SantaTokens and NFTs, leading to a scenario of hyperinflation for both the token and the NFT.

POC

function testMintUnlimitedSantaTokens() public {
address attacker = makeAddr("attacker");
address random = makeAddr("random");
//Santa lets EXTRA_NICE to the attacker
vm.startPrank(santa);
santasList.checkList(attacker, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(attacker, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.warp(santasList.CHRISTMAS_2023_BLOCK_TIME() + 1);
//Attacker mints the NFT and SantaTokens and next transfer the NFT
//to other account to mint new SantaTokens
for(uint256 i = 0; i < 50; i++) {
vm.startPrank(attacker);
santasList.collectPresent();
santasList.transferFrom(attacker, random, i);
vm.stopPrank();
}
assertEq(santaToken.balanceOf(attacker), 1e18 * 50);
}

Tools Used

Manual review.

Recommendations

Implement a mapping to track whether a user has already claimed their present. Integrate it into the collectPresent().

mapping(address => bool) presentClaimed

This ensures that each user can claim the present only once by checking the mapping before processing the function logic.

Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak Already Collected Check

Relying on balanceOf > 0 in collectPresent() allows the msg.sender to send their present to another address and then collect again.

Support

FAQs

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