NFT Dealers

First Flight #58
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

With `cancelListing()` collateral return, it allows minters to mint NFT without collateral

Root + Impact

Description

  • The protocol expect minters to put up lockAmount USDC as collateral for each NFT minting.

  • Now when a minter go through the following flow:
    1. mintNft() <- this call requires the minter to put up a collateral.
    2. list()
    3. cancelListing() <- this call returns the collateral to the minter

    The minter can basically mint NFT for free using this flow.

// Root cause in the codebase with @> marks to highlight the relevant section
function cancelListing(uint256 _listingId) external {
Listing memory listing = s_listings[_listingId];
if (!listing.isActive) revert ListingNotActive(_listingId);
require(listing.seller == msg.sender, "Only seller can cancel listing");
s_listings[_listingId].isActive = false;
activeListingsCounter--;
@> usdc.safeTransfer(listing.seller, collateralForMinting[listing.tokenId]);
@> collateralForMinting[listing.tokenId] = 0;
emit NFT_Dealers_ListingCanceled(_listingId);
}

Risk

Likelihood:

  • When a minter go through the 1) mintNFT, 2) list, 3) cancelListing flow, it can mint NFT for free.

Impact:

  • Going through the 1) mintNFT, 2) list, 3) cancelListing flow multiple times, an attacker can use just lockAmount USDC to mint up to MAX_SUPPLY of NFTs.

Proof of Concept

// A minter go through the mintNft(), list(), and cancelListing() flow will get their collateral back.

Recommended Mitigation

Remove the collateral return logic on cancelList().

The collateral can be returned to the minter when the NFT is sold, logics added inside the buy()function.

function cancelListing(uint256 _listingId) external {
Listing memory listing = s_listings[_listingId];
if (!listing.isActive) revert ListingNotActive(_listingId);
require(listing.seller == msg.sender, "Only seller can cancel listing");
s_listings[_listingId].isActive = false;
activeListingsCounter--;
- usdc.safeTransfer(listing.seller, collateralForMinting[listing.tokenId]);
- collateralForMinting[listing.tokenId] = 0;
emit NFT_Dealers_ListingCanceled(_listingId);
}
Updates

Lead Judging Commences

rubik0n Lead Judge 16 days ago
Submission Judgement Published
Validated
Assigned finding tags:

free-mint-when-cancel

No flag when the listing is canceled.

Support

FAQs

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

Give us feedback!