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

Players Can Still Get Refund and Enter Raffle After Raffle Duration Elapses

Summary

The PuppyRaffle::enterRaffle and PuppyRaffle::refund functions remain callable after the raffleDuration has elapsed, and a winner has not been chosen.

Vulnerability Details

The enterRaffle and refund functions lack input validations that check whether block.timestamp <= raffleStartTime + raffleDuration before proceeding with the rest of the function code.

Proof of Concept

The provided test suite demonstrates the validity and severity of this vulnerability.

How to Run the Test

Requirements:

  • Install Foundry.

  • Clone the project codebase into your local workspace.

Step-by-step Guide to Run the Test:

  1. Ensure the above requirements are met.

  2. Copy the test below and add it to PuppyRaffleTest.t.sol tests.

  3. Paste these events before the setUp function in PuppyRaffleTest.t.sol.

event RaffleEnter(address[] newPlayers);
event RaffleRefunded(address player);
  1. Execute the following command in your terminal to run the test:

forge test --match-test "testEnterRaffleAndRefundAfterRaffleDuration"

Code

function testEnterRaffleAndRefundAfterRaffleDuration()
public
playersEntered
{
vm.warp(block.timestamp + duration + 1);
vm.roll(block.number + 1);
///@notice At this point, the raffle is over, but a winner hasn't been selected yet
address[] memory players = new address[](1);
address playerFive = address(5);
players[0] = playerFive;
///@notice One new player is entered
vm.expectEmit(true, false, false, false);
emit RaffleEnter(players);
puppyRaffle.enterRaffle{value: entranceFee}(players);
///@notice The winner is selected
vm.prank(playerFive);
vm.expectEmit(true, false, false, false);
emit RaffleRefunded(playerFive);
puppyRaffle.refund(4);
}

Impact

Implications:
This vulnerability allows non-active players to enter the game after it has completed and potentially seize the winner's position if timed correctly. Additionally, players can avoid losing their stake by quickly obtaining a refund before a winner is selected.

Exploit Scenario:

  • John participated in a raffle session and lost the round.

  • But before the selectWinner transaction sent by Sarah is processed, John front-runs it with a refund transaction.

  • He promptly exits the game before losing his funds.

Tools Used

  • Foundry

Recommendations

Add a check that ensures enterRaffle and refund are only callable before the raffle duration elapses. This can be implemented as follows:

enterRaffle

function enterRaffle(address[] memory newPlayers) public payable {
+ require(block.timestamp <= raffleStartTime + raffleDuration,"Raffle session end!");
//...
}

refund

function refund(uint256 playerIndex) public {
+ require(block.timestamp <= raffleStartTime + raffleDuration,"Raffle session end!");
address playerAddress = players[playerIndex];
//...
}
Updates

Lead Judging Commences

Hamiltonite Lead Judge about 2 years ago
Submission Judgement Published
Invalidated
Reason: Known issues

Support

FAQs

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

Give us feedback!