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

The total supply value used as the token ID is never updated, causing every subsequent mint to fail after the first successful one

Summary

Implementation of the HorseStore.huff::MINT_HORSE() function does not increment the total supply used to determine the token ID, causing Denial-of-Service (DoS) as it allows only one NFT to be minted.

Vulnerability Details

When minting a horse NFT, assigning a unique token ID to each minted NFT is crucial. In the case of the HorseStore.huff::MINT_HORSE() function, the total supply value is used to determine the token ID. However, the total supply value is never updated. As a result, after the first successful mint, any attempts to mint a new token will fail with an error message ALREADY_MINTED indicating that the token has already been minted.

Impact

Only one NFT can ever be minted.

Proof of Concept (PoC)

Add the next test in HorseStoreHuff.t.sol.

function test_MintingHorseRevertsAfterFirstSuccessfulMint(address randomOwner) public {
vm.assume(randomOwner != address(0));
vm.assume(!_isContract(randomOwner));
uint256 horseId = horseStore.totalSupply();
vm.prank(randomOwner);
horseStore.mintHorse(); // first successful mint
assertEq(horseStore.ownerOf(horseId), randomOwner);
vm.expectRevert("ALREADY_MINTED"); // any mint transactions made after the first mint will be reverted
vm.prank(randomOwner);
horseStore.mintHorse();
}

Run a test with forge test --mt test_MintingHorseRevertsAfterFirstSuccessfulMint.

Tools Used

  • Foundry

Recommendations

NOTE: The mitigation recommended for the current finding includes the mitigation recommended for the finding related to the total supply value not being loaded properly.

The total supply value should be incremented on every successful mint.

Recommended changes to HorseStore.huff::MINT_HORSE() function:

#define macro MINT_HORSE() = takes (0) returns (0) {
[TOTAL_SUPPLY] // [TOTAL_SUPPLY]
+ sload // [totalSupply] mitigation recommended for the finding related to the total supply value not being loaded properly
+ dup1 // [totalSupply, totalSupply] duplicate total supply value
- caller // [msg.sender, totalSupply]
+ caller // [msg.sender, totalSupply, totalSupply] update comment with new stack item
_MINT() // [totalSupply]
+ // Update total supply.
+ 0x1 add // [totalSupply + 1] increment total supply
+ [TOTAL_SUPPLY] // [TOTAL_SUPPLY, totalSupply + 1] push total supply storage slot to the stack
+ sstore // [] store new total supply
stop // []
}

Add the next test in HorseStoreHuff.t.sol.

function test_MintMultipleHorses(uint256 amount) public {
amount = bound(amount, 2, 20);
for (uint256 i = 0; i < amount; ++i) {
uint256 horseId = horseStore.totalSupply();
vm.prank(user);
horseStore.mintHorse();
assertEq(horseStore.ownerOf(horseId), user);
}
uint256 totalSupply = horseStore.totalSupply();
assertEq(totalSupply, amount);
}

Run a test with forge test --mt test_MintMultipleHorses.

Updates

Lead Judging Commences

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

Failure to increment total supply on mint

Failure to properly load the totalSupply in Huff

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

Failure to increment total supply on mint

Failure to properly load the totalSupply in Huff

Support

FAQs

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