NFT Dealers

First Flight #58
Beginner FriendlyFoundry
100 EXP
Submission Details
Impact: low
Likelihood: low

[L-01] Owner Can Whitelist Himself and List NFTs

Author Revealed upon completion

Root Cause:

The owner is explicitly blocked from minting in mintNft() but there is no equivalent restriction in list(), allowing the owner to whitelist himself and list any NFT acquired through a transfer.

Impact: The owner can participate in the marketplace as a seller, creating a conflict of interest since the owner also controls fee collection and whitelist management.

Description

The protocol explicitly prevents the owner from minting NFTs. However the owner can whitelist himself via whitelistWallet() and acquire an NFT through a transfer from another user, then list it on the marketplace. No check exists in list() to prevent this.

function mintNft() external payable onlyWhenRevealed onlyWhitelisted {
@> require(msg.sender != owner, "Owner can't mint NFTs"); // owner blocked from minting
...
}
function list(uint256 _tokenId, uint32 _price) external onlyWhitelisted {
@> // no check preventing owner from listing
require(_price >= MIN_PRICE, "Price must be at least 1 USDC");
require(ownerOf(_tokenId) == msg.sender, "Not owner of NFT");
...
}

Risk

Likelihood: Low

  • Requires the owner to deliberately whitelist himself and acquire an NFT via transfer

  • Not something that happens accidentally

Impact: Low

  • No direct fund loss but creates a conflict of interest

  • Owner could manipulate the marketplace in their favor while also controlling fees and whitelist

Proof of Concept

// PoC: We prove the owner can whitelist himself, acquire an NFT via transfer
// and successfully list it thus bypassing the intended owner restriction
function test_POC_OwnerCanWhitelistHimselfAndList() public revealed {
// Owner whitelists himself
vm.prank(owner);
nftDealers.whitelistWallet(owner);
// Whitelist userWithCash to mint
vm.prank(owner);
nftDealers.whitelistWallet(userWithCash);
// userWithCash mints and transfers NFT to owner
vm.startPrank(userWithCash);
usdc.approve(address(nftDealers), 20e6);
nftDealers.mintNft();
nftDealers.transferFrom(userWithCash, owner, 1);
vm.stopPrank();
// Owner successfully lists the NFT
vm.prank(owner);
nftDealers.list(1, 1000e6);
(address seller,,,, bool isActive) = nftDealers.s_listings(1);
assertEq(seller, owner);
assertTrue(isActive);
}

Recommended Mitigation

function list(uint256 _tokenId, uint32 _price) external onlyWhitelisted {
+ // prevent owner from listing to avoid conflict of interest
+ require(msg.sender != owner, "Owner cannot list NFTs");
require(_price >= MIN_PRICE, "Price must be at least 1 USDC");
require(ownerOf(_tokenId) == msg.sender, "Not owner of NFT");
...
}

Support

FAQs

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

Give us feedback!