The PRNG used to calculate winnerIndex is not strong enough.
winnerIndex is calculated as such:
uint256 winnerIndex = uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length;
msg.sender, block.timestamp, and block.difficulty are all public information.
players.length can be influenced by an attacker by entering or refunding a raffle.
Under these conditions: the attacker could craft a large number of raffle entries. Once the block.timestamp reaches the condition to call selectWinner(), the attacker can find the set of players.length values that would make winnerIndex the same as one of his entries computationally. Then he just needs to either add more entries or remove entries to adjust to the correct value of players.length he needs.
Not necessary, but he can also monitor the mempool and frontrun any attempts by third party to call selectWinner to be more precise in his attack.
Attacker can predict the next values for the PRNG and place himself as the winning index.
Manual Review.
Use Chainlink's PRNG which is unpredictable.
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.