A notable vulnerability exists in the collectPresent
function of the SantasList
smart contract. The function's intent is to prevent users from collecting more than one NFT. However, the current implementation only checks if the caller's balance is greater than zero, neglecting the possibility that a user could transfer their initially collected NFT to another address and then collect an additional NFT. This oversight enables users to potentially collect multiple NFTs by exploiting this loophole.
The issue arises in the conditional check if (balanceOf(msg.sender) > 0), which is designed to ensure a user does not collect more than one NFT. However, this check can be easily circumvented. A user who has already collected an NFT can transfer it to a different address and then call collectPresent again, as their balance would be back to zero, satisfying the function's condition.
In addition to the original issue, a malicious contract could exploit the _checkOnERC721Received
callback, which is typically called during the transfer of an ERC721 token (NFT). This callback can be used to trigger reentrancy attacks. A reentrancy attack occurs when a contract makes an external call to another untrusted contract, which then calls back into the calling contract before the first execution is complete.
In this specific context, a malicious contract could receive an NFT from the collectPresent function and, during the transfer process, use the _checkOnERC721Received
callback to transfer the received NFT and re-enter the collectPresent function. This reentrancy could potentially allow the malicious contract to collect multiple NFTs in a single transaction before the state of the original contract is updated to reflect the first collection, bypassing the intended one-NFT-per-user limitation.
Users can unfairly claim more than their entitled single NFT, undermining the fairness and intended mechanics of the reward distribution.
In the following test case a user successfully collects the present, transfers it to bob's
address and collects another one, which is not the intended system.
Terminal:
Foundry
Introduce a mechanism to track whether a user has already claimed their NFT, ensuring that each eligible user can only collect once, regardless of their current NFT balance.
Add a new mapping to track whether an address has collected an NFT:
Use the mapping to check if already collected:
Relying on balanceOf > 0 in collectPresent() allows the msg.sender to send their present to another address and then collect again.
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.