The Status enum starts with NICE = 0, so both status mappings default to NICE for any address Santa never touched. collectPresent() only checks that both mappings read NICE, so a complete stranger passes both checks and collects an NFT — Santa's list is never consulted at all.
For an address never checked by Santa, s_theListCheckedOnce[addr] and s_theListCheckedTwice[addr] both return the default enum value 0, which is NICE. The NOT_CHECKED_TWICE variant exists in the enum but is never used as a default, so there is no "unchecked" state — every stranger reads as NICE. The same default also makes getNaughtyOrNiceOnce() / getNaughtyOrNiceTwice() report NICE for unchecked addresses.
Likelihood: High — the bug triggers for every address that was never checked, with no special setup; anyone can call collectPresent() after Christmas and receive an NFT.
Impact: High — the protocol's core invariant is broken: presents are supposed to go only to people Santa checked twice as NICE or EXTRA_NICE, but anyone can mint an NFT without Santa's involvement, so the naughty/nice list is meaningless and the NFT supply is unlimited.
A never-checked address calls collectPresent() after Christmas and receives an NFT. Note the two getter calls returning NICE for an address Santa never touched.
Make the first enum value an explicit "not checked" state so an unchecked address can never read as NICE, or track checked-ness with a separate boolean.
## Description `collectPresent` function is supposed to be called by users that are considered `NICE` or `EXTRA_NICE` by Santa. This means Santa is supposed to call `checkList` function to assigned a user to a status, and then call `checkTwice` function to execute a double check of the status. Currently, the enum `Status` assigns its default value (0) to `NICE`. This means that both mappings `s_theListCheckedOnce` and `s_theListCheckedTwice` consider every existent address as `NICE`. In other words, all users are by default double checked as `NICE`, and therefore eligible to call `collectPresent` function. ## Vulnerability Details The vulnerability arises due to the order of elements in the enum. If the first value is `NICE`, this means the enum value for each key in both mappings will be `NICE`, as it corresponds to `0` value. ## Impact The impact of this vulnerability is HIGH as it results in a flawed mechanism of the present distribution. Any unchecked address is currently able to call `collectPresent` function and mint an NFT. This is because this contract considers by default every address with a `NICE` status (or 0 value). ## Proof of Concept The following Foundry test will show that any user is able to call `collectPresent` function after `CHRISTMAS_2023_BLOCK_TIME` : ``` function testCollectPresentIsFlawed() external { // prank an attacker's address vm.startPrank(makeAddr("attacker")); // set block.timestamp to CHRISTMAS_2023_BLOCK_TIME vm.warp(1_703_480_381); // collect present without any check from Santa santasList.collectPresent(); vm.stopPrank(); } ``` ## Recommendations I suggest to modify `Status` enum, and use `UNKNOWN` status as the first one. This way, all users will default to `UNKNOWN` status, preventing the successful call to `collectPresent` before any check form Santa: ``` enum Status { UNKNOWN, NICE, EXTRA_NICE, NAUGHTY } ``` After modifying the enum, you can run the following test and see that `collectPresent` call will revert if Santa didn't check the address and assigned its status to `NICE` or `EXTRA_NICE` : ``` function testCollectPresentIsFlawed() external { // prank an attacker's address vm.startPrank(makeAddr("attacker")); // set block.timestamp to CHRISTMAS_2023_BLOCK_TIME vm.warp(1_703_480_381); // collect present without any check from Santa vm.expectRevert(SantasList.SantasList__NotNice.selector); santasList.collectPresent(); vm.stopPrank(); } ```
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.