The SpookySwap
contract allows users to purchase NFTs with variable pricing scenarios through the trickOrTreat
function. However, due to insufficient access control in the resolveTrick
function, the contract is vulnerable to a Double-Selling Vulnerability. This flaw allows multiple buyers to pay for the same pending NFT, which could lead to financial losses for buyers and revenue discrepancies for the contract.
Vulnerability Details
The double-selling vulnerability occurs in the resolveTrick
function, where NFTs in a pending state (due to incomplete payment under a double-price scenario) can be completed by any buyer rather than only the original buyer. The sequence of events is as follows:
If a buyer initiates a purchase in the double-price scenario and sends less than the required ETH, the NFT is minted to the contract’s address, marking it as pending until the buyer completes payment via resolveTrick
.
The resolveTrick
function does not restrict access to only the original buyer, meaning other users can attempt to complete the transaction by submitting additional payments, even if they were not the initial buyer.
This lack of restriction allows multiple buyers to each pay for the same NFT, although only one NFT is available to be transferred.
Impact
This vulnerability creates significant risks:
Financial Loss for Buyers: Multiple buyers could each pay for the same NFT, expecting to receive it. However, only one NFT exists, resulting in financial losses for those who do not receive the NFT.
Revenue and Inventory Discrepancies**: The contract may collect excess funds while transferring only one NFT, leading to revenue discrepancies and potential disputes.
Reputation Damage: The vulnerability may reduce buyer confidence, as users could perceive the contract as unreliable or prone to exploitation.
Tools Used
Tests
Recommendations
Restrict resolveTrick
Access to the Original Buyer:
Modify resolveTrick
to enforce that only the original buyer can complete the transaction by checking that msg.sender
matches the address stored in pendingNFTs[tokenId]
. This will prevent unauthorized buyers from attempting to complete another buyer’s pending purchase.
Example:
Implement Expiration for Pending NFTs:
Introduce an expiration period for pending NFTs to ensure they do not remain indefinitely locked if the original buyer does not complete the transaction. If the buyer does not complete the payment within the set time, the NFT should expire, allowing the contract owner to reclaim or relist it.
Example:
Add Events for Transparency:
Emit events for the creation and completion of pending mints, including buyer address and token ID, to improve transaction transparency. This can help buyers track their transaction status and prevent misunderstandings.
Example:
These mitigations will prevent unauthorized buyers from completing a pending purchase, limit the time pending NFTs remain in limbo, and improve transparency, strengthening the SpookySwap
contract’s reliability and user trust.
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.