Puppy Raffle

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

No Maximum Players Limit

Root + Impact

Description

  • * The `enterRaffle()` function does not enforce any maximum limit on the number of players that can enter a raffle. Players can be added indefinitely until the array grows extremely large.

    * Without limits, a malicious actor could fill the array with thousands of entries, causing gas limit issues when `selectWinner()` is called or making the contract unusable due to excessive gas costs in operations that iterate over the array.

    ```solidity:79:92:src/PuppyRaffle.sol

    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++) {

    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);

    }

    ```


Risk

Likelihood:

  • * This occurs when attackers or users add excessive numbers of players to the raffle

    * A single malicious transaction could add hundreds or thousands of players

    * The O(n²) duplicate check makes this even more problematic as array grows

Impact:

  • * Gas limit DoS attacks - `selectWinner()` may exceed block gas limits

    * Unbounded gas costs for all operations that iterate over players array

    * Contract becomes unusable if array grows too large

    * Potential for permanent DoS if array size prevents winner selection

Proof of Concept

```solidity
// Attacker enters with 1,000 addresses in one transaction
address[] memory manyPlayers = new address[](1000);
for (uint256 i = 0; i < 1000; i++) {
manyPlayers[i] = address(uint160(i + 1000));
}
puppyRaffle.enterRaffle{value: entranceFee * 1000}(manyPlayers);
// Now players.length = 1000+
// selectWinner() must iterate over all players
// Winner selection and other operations become extremely expensive
// May exceed block gas limits
```

Recommended Mitigation

```diff
+ uint256 public constant MAX_PLAYERS_PER_ENTRY = 100;
+ uint256 public constant MAX_TOTAL_PLAYERS = 1000;
function enterRaffle(address[] memory newPlayers) public payable {
+ require(newPlayers.length > 0, "PuppyRaffle: Must provide at least one player");
+ require(newPlayers.length <= MAX_PLAYERS_PER_ENTRY, "PuppyRaffle: Too many players per entry");
+ require(players.length + newPlayers.length <= MAX_TOTAL_PLAYERS, "PuppyRaffle: Raffle is full");
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
// ... rest of function
}
```
This prevents unbounded array growth and protects against DoS attacks.
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 16 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!