Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Flawed Present Receiver Tracking Enables Unlimited ERC20 Minting for "EXTRA_NICE" Accounts

Summary

Insufficient check for presents received with balanceOf(msg.sender) > 0) allows infinite ERC20 printing from attacker with SantasList::Status.EXTRA_NICE

Vulnerability Details

The absence of a recording mechanism for present receivers and relying only on balanceOf(msg.sender) > 0 allows user with EXTRA_NICE status to move received tokens to another address and continue to loop through the collectPresent() function as much as block gas limit allows.

Impact

Initially, after Santa user gives EXTRA_NICE status to the user, user is able to pass

if (balanceOf(msg.sender) > 0) {revert ...}
...
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE

requirements and mint fungible and non-fungible tokens

_mintAndIncrement();
i_santaToken.mint(msg.sender);

Then to enter collectPresent() again and get around balanceOf(msg.sender) > 0) user can transfer NFT to another address.

Foundry tests will look like this:

function test_mintInfiniteTokens() public {
vm.startPrank(santa);
santasList.checkList(user, SantasList.Status.EXTRA_NICE);
santasList.checkTwice(user, SantasList.Status.EXTRA_NICE);
vm.stopPrank();
vm.startPrank(user);
for (uint256 i; i < 69; i++) {
santasList.collectPresent();
santasList.transferFrom(user, userBag, i);
}
assertEq(santaToken.balanceOf(user), 69e18);
vm.stopPrank();
}

Full test on GitHub repo fork

Tools Used

Foundry

Recommendations

Introduce a list of persons that already received the present:

+ mapping(address => bool) public presentsReceived;
function collectPresent() external {
if (block.timestamp < CHRISTMAS_2023_BLOCK_TIME) {
revert SantasList__NotChristmasYet();
}
- if (balanceOf(msg.sender) > 0) {
+ if(presentsReceived[msg.sender])
revert SantasList__AlreadyCollected();
}
if (s_theListCheckedOnce[msg.sender] == Status.NICE && s_theListCheckedTwice[msg.sender] == Status.NICE) {
+ presentsReceived[msg.sender] = true;
_mintAndIncrement();
return;
} else if (
s_theListCheckedOnce[msg.sender] == Status.EXTRA_NICE
&& s_theListCheckedTwice[msg.sender] == Status.EXTRA_NICE
) {
+ presentsReceived[msg.sender] = true;
_mintAndIncrement();
i_santaToken.mint(msg.sender);
return;
}
revert SantasList__NotNice();
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak Already Collected Check

Relying on balanceOf > 0 in collectPresent() allows the msg.sender to send their present to another address and then collect again.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.