The winnerIndex
is deterministic.
An attacker can pre-compute this value then stuff the entries to the raffle such that calling selectWinner()
results in the attacker always winning the prizePool
.
enterRaffle
stories raffle entries in an array.
The winnerIndex
calculation is deterministic i.e. no source of randomness is used.
The following inputs to the computation can be known or controlled by the attacker:
msg.sender
(the attacker's address)
block.timestamp
block.difficulty
(deprecated and is equivalent to block.prevrandao
)
players.length
(controlled by stuffing entries)
The selectWinner()
function can be called by anyone willing to pay the gas.
Loss of funds: An attacker can guarantee they always win the prizePool
thus unfairly obtaining funds without risking anything.
The attacker can flashloan funds to stuff the entry pool in the same block that he calls selectWinner()
Foundry
selectWinner() should be callable only by a keeper who provides a secure randomness oracle for the computation of the winner.
A randomness oracle can be used as an input to the winnerIndex computation.
Attacker: The attacker pre-computes the winning index then stuffs the raffle with entries to ensure PuppyRaffle computes the desired winnerIndex.
Victim: Participants in the raffle pay an entry fee to add their addresses to the raffle.
Protocol: PuppyRaffle contract's collects entry fees and 80% of the totalAmountCollected
is paid to the winner.
This test-case should be added to the PuppyRaffleTest.t.sol::PuppyRaffle contract.
The Exploit contract should be added to the PuppyRaffleTest.t.sol file.
The expected result is that address(exploit).balance == prizePool
. This can be seen by running:
Root cause: bad RNG Impact: manipulate winner
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.