Root + Impact
The _mintAndIncrement() function uses OpenZeppelin's _safeMint(), which calls onERC721Received() on the recipient if it's a smart contract. This is an external call.
In collectPresent(), the AlreadyCollected check uses balanceOf(msg.sender) > 0. If a malicious contract receives the NFT via _safeMint, its onERC721Received callback fires. Inside this callback, the attacker can transfer the NFT to another address (making balanceOf return 0 again), then re-call collectPresent().
This allows an EXTRA_NICE user to collect multiple NFTs and SantaTokens by reentering through the ERC721 callback.
Likelihood:
Requires deploying a contract that implements onERC721Received and transfers the NFT away before re-calling collectPresent()
Moderately complex but well-known attack pattern
Impact:
EXTRA_NICE attacker can mint unlimited NFTs and unlimited SantaTokens (1e18 per reentry)
NICE attacker can mint unlimited NFTs
Completely breaks the "collect once" invariant
Use a dedicated hasClaimed mapping instead of relying on balanceOf:
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.