After buy() completes, the seller calls collectUsdcFromSelling(tokenId) to receive proceeds. The listing data persists at s_listings[tokenId] with isActive = false.
list() stores new listings at the same s_listings[_tokenId] slot. When the buyer relists the NFT, the original seller's address is overwritten. Their collectUsdcFromSelling reverts on onlySeller because the seller field now points to the new owner.
Likelihood:
Any buyer who relists before the previous seller collects triggers this — normal marketplace activity, no malice required
Impact:
Seller permanently loses sale proceeds plus minting collateral with no recovery path
Run with forge test --match-test testExploit_ListingOverwrite. Alice's collectUsdcFromSelling reverts because s_listings[1].seller now points to Bob. Alice's 119 USDC (99 proceeds + 20 collateral) is permanently locked.
Use listingsCounter as the storage key instead of tokenId, so each sale gets its own slot that is never overwritten by future listings of the same NFT. This ensures the original seller's listing data persists until they collect.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.