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.