transferFrom in _executeSale and unlistNFT risks sending NFTs to non-ERC721-compliant contracts, causing permanent asset lossThe contract uses transferFrom to transfer NFTs in both the BidBeastsNFTMarketPlace::_executeSale and BidBeastsNFTMarketPlace::unlistNFT functions (lines 213 and 97, respectively):
Unlike safeTransferFrom, transferFrom does not verify if the recipient contract implements onERC721Received, as required by the ERC721 standard. If the recipient is a non-compliant contract (e.g., lacking onERC721Received or NFT management logic), the transfer succeeds, but the NFT becomes permanently locked, as the contract cannot approve or transfer it out.
This violates best practices (e.g., OpenZeppelin's recommendation to use safeTransferFrom) and risks user asset loss, especially for bidders using smart contract wallets or sellers unlisting to their own non-compliant contracts.
Likelihood: Medium
Most bidders use EOAs or ERC721-compliant wallets, but smart contract wallets (e.g., misconfigured Gnosis Safe) are plausible.
Impact: High
Affected users lose their NFTs permanently, with no protocol-wide impact but significant loss for individuals.
Add this NonCompliantReceiver contract in the test file:
After that, add this particular test_NFTLockedInNonCompliantContract test in the test file:
Run the above test using the command:
Although the straightforward suggestion would be to replace transferFrom with safeTransferFrom, but it has some caveats. With this direct replacement, the contract is at risk of either some reentrancy or DoS attacks, or both. This is because the recipient contract's onERC721Received function could contain malicious code that exploits the transfer process. Here's a good write-up about safeTransferFrom by RareSkills: Safe Transfers: safeTransferFrom, _safeMint, and the onERC721Received function, definitely worth a read.
Thus, it's better to implement a pull-based transfer mechanism, along with safeTransferFrom, where the contract credits the NFT to the recipient (by using mapping), and the recipient can then call a function to claim the NFT. This way, the transfer is initiated by the recipient, reducing the risk of reentrancy or DoS attacks.
Non-safe transferFrom calls can send NFTs to non-compliant contracts, potentially locking them permanently.
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.