Note:
This was reported to Zora but the contract in question is depreciated.
Link to the report.
TLDR
Zora’s built-in NFT marketplace lets operators accept bids using any ERC20 token. A malicious operator can exploit this by creating a custom ERC20 token that triggers external marketplace interactions during transfer. This allows the operator to sell an NFT to a buyer on another marketplace legitimately, then immediately steal the NFT back using Zora’s transfer logic, leaving the buyer empty-handed while keeping both the NFT and payment.
details.
Zora’s NFT marketplace is designed with flexibility in mind, allowing users to trade NFTs using any arbitrary ERC20 token. While flexible, this design carries implicit risks. Specifically, Zora’s marketplace does not properly account for scenarios where a malicious ERC20 token might execute custom logic during the bid finalization step, resulting in unintended state changes.
In simpler terms, Zora’s marketplace assumes ERC20 token transfers or approval calls are passive operations. However, a malicious operator can create custom ERC20 tokens containing active logic (hooks) that interact with external marketplaces, manipulating NFT ownership states mid-transaction.
Step 1: NFT Listing and Bidding (External Marketplace)
• An operator mints a Zora NFT.
• The operator lists this NFT on an external marketplace (e.g., OpenSea).
• A customer sees the NFT and places a bid on the external marketplace.
Step 2: Malicious ERC20 Token Setup (Zora Marketplace)
• The operator creates a custom ERC20 token under their complete control.
• Using Zora’s built-in marketplace, the operator places a bid on his own NFT using this malicious ERC20 token.
Step 3: Initiating the Exploit (Accepting Malicious Bid)
• The operator accepts his malicious bid via Zora’s marketplace.
• This triggers Zora’s internal _finalizeTransfer() function to transfer the NFT.
Step 4: Malicious Logic Executes During Transfer
• During _finalizeTransfer(), Zora’s marketplace invokes the malicious ERC20 token’s logic.
• This custom ERC20 logic interacts with the external marketplace, automatically accepting the legitimate customer’s bid from Step 1.
• The NFT is transferred from the operator to the customer, and payment is transferred to the operator.
Step 5: YOINK
• Execution context now returns to Zora’s marketplace after the external sale.
• Zora’s marketplace incorrectly assumes the NFT is still held by the operator. Due to this assumption, the marketplace proceeds to transfer the NFT from the customer to the operator.
Final Outcome:
• The customer loses ownership of the NFT they purchased.
• The operator retains both the customer’s payment and the NFT itself.
