mintNft collects lockAmount USDC as collateral from the minter, stores it in collateralForMinting[tokenId], and then mints the NFT to the caller using _safeMint.
_safeMint triggers the onERC721Received callback on the recipient if it is a contract. At the point the callback fires, collateralForMinting[tokenId] has already been set but the mint is not yet complete. A whitelisted attacker contract uses this window to call list() (ownership check passes because ERC721 state is updated before the callback) and immediately cancelListing(), which refunds the full collateralForMinting[tokenId] — resulting in a zero-net-cost mint. There is no reentrancy guard on any of these functions.
Likelihood:
Any whitelisted address that is a smart contract can trigger this — whitelisted users are normal marketplace participants, not privileged admins.
The exploit is fully deterministic and requires no external conditions beyond holding a whitelist slot.
Impact:
Attacker receives the minted NFT at zero cost (collateral fully recovered via cancelListing).
Repeated across MAX_SUPPLY mints, all minting collateral locked by other honest minters can be drained.
Add MintReentryAttacker outside NFTDealersTest (e.g., at the bottom of the file), then paste testPoC_SafeMintReentrancy inside NFTDealersTest. Run:
forge test --match-test testPoC_SafeMintReentrancy -vvvv
Add a nonReentrant modifier (from ReentrancyGuard) to all state-mutating functions that touch collateralForMinting or perform external calls. This closes the current vector and any future cross-function reentrancy paths in the contract.
nonReentrant blocks any reentrant call into the contract while a guarded function is executing, preventing the onERC721Received callback from calling list / cancelListing and draining collateralForMinting.
This is a real reentrancy point, but not an exploitable one. The transaction will revert on the second ERC721 transfer.
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.