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

`enterRaffle` address(0) input will make `selectWinner` fail

Summary

The function enterRaffle doesn't ensure that address(0) is not passed within the newPlayers array. If selectWinner function will ever pick a address(0) winner, it will fail due to ERC721: mint to the zero address.

Vulnerability Details

The _safeMint function in OZ's ERC721 implementation calls the _mint function from the same place which looks as follows:

function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");

PoC

function testEnter4Zero() public {
address[] memory players = new address[](4);
players[0] = playerOne;
players[1] = playerTwo;
players[2] = playerThree;
players[3] = address(0);
vm.warp(block.timestamp + duration + 1);
vm.roll(block.number + 1);
puppyRaffle.enterRaffle{value: entranceFee * 4}(players);
puppyRaffle.selectWinner();
}

This fails in 25% of the cases.

forge test --mt testEnter4Zero

Ran 1 test suites: 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[FAIL. Reason: ERC721: mint to the zero address] testEnter4Zero() (gas: 204625)

Impact

In case of low participation the enterRaffle has a reasonable chance to fail due to address(0) winning the NFT that can't be minted to address(0). Making interested parties to call the function again and again until a non zero address wins.

Tools Used

Manual review

Recommendations

function enterRaffle(address[] memory newPlayers) public payable {
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
for (uint256 i = 0; i < newPlayers.length; i++) {
++ require(newPlayers[i] != address(0), "PuppyRaffle: Address 0 not allowed")
players.push(newPlayers[i]);
}
// Check for duplicates
for (uint256 i = 0; i < players.length - 1; i++) {
for (uint256 j = i + 1; j < players.length; j++) {
require(players[i] != players[j], "PuppyRaffle: Duplicate player");
}
}
emit RaffleEnter(newPlayers);
}
Updates

Lead Judging Commences

Hamiltonite Lead Judge about 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

zero address can win the raffle

Funds are locked to no one. If someone gets the refund issue, they also got this issue. IMPACT: High Likelihood: High

Support

FAQs

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

Give us feedback!