The buy() function only takes a listing ID. It reads the price from storage at execution time, with no way for the buyer to say "I'm willing to pay at most X." A malicious seller can watch the mempool, see an incoming buy() transaction, and front-run it with updatePrice() to jack up the price right before the buyer's transaction lands.
If the buyer approved a large amount of USDC (infinite approvals are standard practice in DeFi), they silently pay the inflated price with no recourse.
Likelihood: Front-running is practical on all major EVM chains. The seller just needs to submit updatePrice with higher gas. MEV bots make this even easier.
Impact: The buyer pays up to type(uint32).max (~4,294 USDC) or the full extent of their USDC approval — whichever is lower. For users with infinite approvals, this can mean losing thousands of dollars on what was supposed to be a cheap purchase.
Alice lists NFT #1 at 10 USDC.
Bob approves unlimited USDC and submits buy(1).
Alice sees Bob's pending tx, front-runs with updatePrice(1, 4000e6).
Bob's buy(1) reads the new price — 4,000 USDC — and pays it.
Bob spent 400x what he expected. No warning, no revert.
Add a maxPrice parameter so the buyer can cap what they're willing to pay. This is standard slippage protection — the same pattern used by Uniswap, OpenSea, and virtually every DeFi protocol.
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.