mintNft allows reentrancy, enabling an attacker to mint multiple NFTs and corrupt collateral accountingmintNft() collects USDC collateral from the caller, increments the token counter, records the collateral mapping, and mints the NFT — intended to execute atomically for one NFT per call.
The external call to usdc.transferFrom() is made before tokenIdCounter is incremented and before collateralForMinting is written, violating the Checks-Effects-Interactions pattern. A reentrant call during the external transfer finds the contract in its pre-mint state, passing all checks and minting again before any state is committed.
Likelihood:
A whitelisted attacker deploys a contract that implements an ERC777 tokensReceived hook, and the protocol accepts that token as the USDC address — reentrancy executes automatically on every transfer.
The _safeMint call also triggers onERC721Received on recipient contracts, giving a second reentrancy entry point even with a standard ERC20, as state updates have already been incorrectly ordered.
Impact:
An attacker mints multiple NFTs for the price of one, exceeding intended per-wallet or supply limits.
collateralForMinting is written with a stale tokenIdCounter, corrupting the collateral record for every reentrant mint — breaking future refunds, resale collateral checks, and fee withdrawals for affected token IDs.
Move all state updates above every external call so the contract's state is fully committed before any external code can execute.
Consider also adding OpenZeppelin's ReentrancyGuard as a defense-in-depth measure, since _safeMint independently triggers onERC721Received on recipient contracts.
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.