The EggHuntGame contract uses a flawed pseudo-random number generator (PRNG) in the searchForEgg function, which relies on block.timestamp, block.prevrandao, msg.sender, and eggCounter to determine if a player finds an egg. This approach introduces vulnerabilities that allow malicious users to manipulate or predict the outcome, undermining the game's fairness and security.
The PRNG formula:
is vulnerable to manipulation and front-running due to:
block.timestamp: Set by miners and can be manipulated within a small window (±15 seconds). Attackers can time transactions to exploit this.
msg.sender: The attacker can control this by using multiple addresses to precompute and choose the optimal one.
eggCounter: A predictable state variable that increments only when an egg is found. Attackers can observe its current value and compute the random number in advance.
An attacker can:
Precompute the random number for multiple addresses (using known block.prevrandao, block.timestamp, and eggCounter).
Select the address that guarantees a result below the eggFindThreshold (e.g., 20%).
Submit a transaction with the chosen address to "win" an egg.
This allows attackers to bypass the 20% chance and reliably find eggs, defeating the game's randomness.
The searchForEgg function lacks checks to ensure users are valid participants (e.g., requiring a minimum stake or NFT ownership). This increases the risk of spam attacks and abuse.
Loss of Fairness: Attackers can manipulate the outcome, making the game unfair for legitimate users.
Gas War Exploits: Malicious users may engage in gas bidding wars to control block timestamps or transaction order, further destabilizing the system.
Financial Loss: The game’s value diminishes if users lose trust in its fairness.
Solidity Static Analysis
Manual Code Review
Security Patterns for Random Number Generation
Replace the PRNG with a Chainlink VRF (Verifiable Random Function) or a similar oracle service. These provide:
Unpredictability: Randomness is generated off-chain and verified on-chain.
Tamper-Proof: Attackers cannot precompute or influence the result.
Add checks to ensure users meet criteria (e.g., holding an NFT or paying a fee) before participating.
Block variables like block.timestamp, block.prevrandao, and msg.sender should never be used alone for critical randomness.
Avoid using mutable state variables (e.g., eggCounter) in the random number calculation. Instead, use a fixed seed or a secure RNG output.
Attack Steps:
Observe eggCounter and block.prevrandao (from the previous block).
Precompute the random number for multiple addresses.
Choose an address where the random result is below eggFindThreshold.
Submit a transaction with that address to guarantee an egg.
Mitigation Check:
Replace the PRNG with Chainlink VRF:
The current PRNG implementation is insecure and exploitable. Adopting a verifiable random number generator like Chainlink VRF is critical to ensure fairness and prevent manipulation.
Insecure methods to generate pseudo-random numbers
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.