The selectWinner() function uses _safeMint() after sending ETH to the winner. The _safeMint() function calls onERC721Received() on the recipient if it's a contract. This creates two issues: 1) If the winner is a smart contract wallet that doesn't implement onERC721Received(), the transaction reverts and the raffle cannot complete, 2) The winner contract can intentionally revert in onERC721Received() to DoS the raffle if they don't like the NFT rarity they would receive.
Likelihood:
The function performs the following steps:
Sends ETH to the winner using a low-level call
Mints an NFT to the winner using _safeMint
The _safeMint call triggers onERC721Received if the recipient is a contract. A malicious contract can deliberately revert during this callback (e.g., based on NFT rarity), causing the entire selectWinner execution to revert.
Since the raffle state is finalized inside this function, repeated reverts result in a Denial of Service, preventing the raffle from ever completing.
Impact:
The raffle can be permanently stuck if a smart contract wallet wins but doesn't implement ERC721Receiver. Additionally, malicious players can grief the protocol by reverting when they would receive common NFTs, forcing the raffle to remain unresolved.
A malicious contract can revert during NFT receipt:
Use a pull pattern where winners claim their prizes, or use regular _mint() instead of _safeMint():
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.