NFT Dealers

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

Reentrancy In buy function

Author Revealed upon completion

State update after externall call, Allow buying teh same NFT multiple times

Description

  • after Buying the NFT the state should update before any externall call should follow Checks-Effects-Interactions pattern

  • The state updated after the NFT was send to the buyer allow reentrancy

function buy(uint256 _listingId) external payable {
Listing memory listing = s_listings[_listingId];
if (!listing.isActive) revert ListingNotActive(_listingId);
require(listing.seller != msg.sender, "Seller cannot buy their own NFT");
activeListingsCounter--;
bool success = usdc.transferFrom(msg.sender, address(this), listing.price);
require(success, "USDC transfer failed");
_safeTransfer(listing.seller, msg.sender, listing.tokenId, "");
//@> s_listings[_listingId].isActive = false;
emit NFT_Dealers_Sold(msg.sender, listing.price);
}

Risk

Likelihood:

  • Reason 1: Any attacker can deploy a malicious contract implementing onERC721Received.

  • Reason 2: Reentrancy is easy to exploit when state updates happen after external calls.

Impact:

  • Impact 1 Attacker can buy the same NFT multiple times in a single transaction (reentrancy loop)

  • Impact 2: Attacker can buy the same NFT multiple times in a single transaction

Proof of Concept

Attacker deploys a malicious contract with onERC721Received():
Inside it, calls buy(_listingId) again.
Attacker calls:
buy(_listingId);
Flow:
_safeTransfer → triggers onERC721Received
Reenters buy() before isActive = false
Repeats multiple times

Recommended Mitigation

follow Checks-Effects-Interactions apttern

- _safeTransfer(listing.seller, msg.sender, listing.tokenId, "");
s_listings[_listingId].isActive = false;
+ s_listings[_listingId].isActive = false;
_safeTransfer(listing.seller, msg.sender, listing.tokenId, "");
+ ReentrancyGuard

Support

FAQs

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

Give us feedback!