Puppy Raffle

AI First Flight #1
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

H-5: Arithmetic overflow in enterRaffle() allows free raffle entries

Description

Severity: High

The enterRaffle() function at PuppyRaffle.sol:82 checks that msg.value matches the total entrance fee:

require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");

Since Solidity 0.7.6 has no built-in overflow protection, the multiplication entranceFee * newPlayers.length can overflow uint256 and wrap back to a small value or zero. An attacker can craft a newPlayers array length such that the product overflows to exactly match a small msg.value (including zero), entering many players for free.

Proof of Concept

function testOverflowEnterRaffle() public {
// Set entranceFee to just above half of uint256 max
uint256 overflowFee = type(uint256).max / 2 + 1;
PuppyRaffle overflowRaffle = new PuppyRaffle(overflowFee, feeAddress, duration);
address[] memory players = new address[](2);
players[0] = playerOne;
players[1] = playerTwo;
// overflowFee * 2 overflows uint256 back to 0
// Attacker pays 0 ETH but enters 2 players
overflowRaffle.enterRaffle{value: 0}(players);
// Both players are now in the raffle without paying
assertEq(overflowRaffle.getActivePlayerIndex(playerOne), 0);
assertEq(overflowRaffle.getActivePlayerIndex(playerTwo), 1);
}

With lower entrance fees, the attacker needs a longer array, but the principle holds: for any entranceFee > 0, there exists a newPlayers.length that causes entranceFee * newPlayers.length to overflow to zero.

Risk

  • Impact: High — attacker enters unlimited players for free, gaining unfair advantage in the raffle. They can also immediately refund() all entries to extract ETH from the contract.

  • Likelihood: Medium — requires a specific array length to trigger the overflow, but the computation is trivial off-chain.

Recommended Mitigation

Use SafeMath or check for overflow at PuppyRaffle.sol:82:

import "@openzeppelin/contracts/math/SafeMath.sol";
using SafeMath for uint256;
function enterRaffle(address[] memory newPlayers) public payable {
require(msg.value == entranceFee.mul(newPlayers.length), "PuppyRaffle: Must send enough to enter raffle");
// ...
}

Alternatively, upgrade to Solidity >=0.8.0 where arithmetic overflow reverts by default.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 4 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!