The current implementation of randomness in the ChoosingRam:selectRamIfNotSelected function uses a combination of block.timestamp
and block.prevrandao
hashed together and then applies modulo tokenCounter
to determine a random number. This method is predictable, allowing a malicious organizer to potentially manipulate the outcome or predict the result ahead of time. As the organizer may have influence over or foreknowledge of these block values, they can exploit this to ensure a specific participant, including themselves, wins.
The current random number generation method in ChoosingRam:selectRamIfNotSelected is:
This approach is weak because:
block.timestamp can be influenced by the validator within certain bounds.
block.prevrandao is accessible and predictable for validators.
The tokenCounter can be manipulated through continued NFT minting with the RamNFT:mintRamNFT
method after the event has closed.
These factors combined allow an organizer to predict or manipulate the outcome, especially when they have knowledge of or control over block parameters.
The organizer if a validator or working with one can know ahead of time the block.timestamp
and block.prevrandao
and use that knowledge to predict when to select the winner. See the solidity blog on prevrando here. block.difficulty
was recently replaced with prevrandao
. Although the hashed result of these two values then applies modulo tokenCounter
, the organizer can still manipulate the tokenCounter
value to result in their index being the winner because the 'RamNFT:mintRamNFT` function is not restricted after the event has ended.
If the organizer or an accomplice is a participant, they can manipulate the randomness to select themselves as the winner, leading to unfair outcomes and potential financial loss for other participants. This predictability undermines trust in the event's fairness.
Manual Review
Start by preventing the minting of NFTs using the RamNFT:mintRamNFT
method once the event has ended. Consider using an oracle for your randomness like Chainlink VRF. It is capable of providing a secure and verifiable source of randomness on-chain for a number found within a range.
The organizer is trusted, but the function `ChoosingRam::selectRamIfNotSelected` uses a way to generate a random number that is not completely random.
The organizer is trusted, but the function `ChoosingRam::selectRamIfNotSelected` uses a way to generate a random number that is not completely random.
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.