selectWinner() derives both the winner index and the puppy rarity from keccak256 over values the caller can observe or control — there is no commit-reveal, VRF, or other unbiasable entropy source:
Attack prerequisites are trivially met by any participant:
The attacker contract simulates the exact formula off-chain, scans for a timestamp at which players[winnerIndex] is itself, and only then submits selectWinner(). The same predictability applies to the rarity roll, letting the attacker also bias toward the legendary puppy. The raffle's core fairness guarantee collapses into a deterministic win for whoever bothers to compute.
Likelihood: High — any participant can deploy the predictor contract; the computation is pure keccak over public inputs, requiring no privileged access or miner collusion.
Impact: High — the attacker deterministically steals the 80% prize pool and the minted puppy, turning a probabilistic raffle into a guaranteed payout for the sophisticated player.
The Foundry test below demonstrates the deterministic win:
Test assertions and measured result (forge test --match-test test_PoC_M1_WinnerPredictable):
Source the randomness from Chainlink VRF (or a commit-reveal scheme) instead of caller-influenced block data. VRF delivers the random word via a verifiable secret the caller cannot predict or bias at call time, so precomputing the winner becomes impossible and the raffle's probabilistic fairness is restored. Never derive draw randomness solely from msg.sender, block.timestamp, or block.difficulty/prevrandao.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.