The SantasList::collectPresent function should allow collecting present if the caller is nice or extra nice. Also, the addresses should not be able to collect more than once. Therefore, there is a check if the balance of msg.sender is greather than zero. The problem is that the user can collect his present, then transfer it to another address and collect again bypassing the balanceOf check.
The user that is nice or extra nice can collect more than once in the SantasList::collectPresent function. The function uses balanceOf(msg.sender) to check that the user is already collected. But this statement can be easily manipulated by transferring the collecting present to another address. In this case the balance of msg.sender will be again 0 and the check will be passed.
The impact of this vulnerability is that the nice and extra nice users can collect their present more than once.
Let's consider the following scenario:
Bob has NICE status to be eligible for collectPresent.
Bob calls collectPresent function to mint an NFT.
Bob's balance is 1 after collecting.
Bob transfers his NFT to another address - Alice.
Bob calls collectPresent again.
In the file SantasListTest.t.sol there is a test function that shows that the user can't collect more than once. But this test function does not take into account that the user can transfer his token before calling again the collectPresent function.
The following test function demonstrates how a nice user (Bob) can bypass the balanceOf check and collect more than once:
You can add this function to the SantasListTest.t.sol and execute it using Foundry and the following command: forge test --match-test testUserCanCollectPresentMoreThanOnce
VS Code, Foundry
You can add a mapping that track if an address has collected a present and a function that checks if an address has already collected:
With these changes, the collectPresent function now checks the s_hasCollected mapping to determine if the caller has already collected a present. If he has, the function reverts with the SantasList__AlreadyCollected error. After successfully collecting a present, the user's address is marked as having collected in the s_hasCollected mapping, preventing them from collecting again in the future. The additional hasCollected function is a convenience method that allows anyone to check if a particular address has already collected a present.
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.