Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Anyone Can Spam searchForEgg Without Limits

📄 Summary

The EggHuntGame contract does not impose any rate-limiting or cooldown on user interactions with the searchForEgg() function. This allows participants to repeatedly call the function within a single block or across multiple blocks, exploiting the egg-finding mechanism by brute force. This undermines the game's fairness, causes economic imbalance, and can lead to network congestion or front-running via private transactions.


🛠️ Vulnerability Details

Contract:

EggHuntGame.sol

Function:

function searchForEgg() external

Problem:

The function uses a pseudo-random number to determine if a user finds an egg:

uint256 random = uint256(
keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender, eggCounter))
) % 100;
if (random < eggFindThreshold) {
...
}

However, there are no limits on how many times a single user can call searchForEgg(). Since the function is publicly accessible and relies on weak randomness, attackers can:

  • Call the function repeatedly in a single block (via private RPCs or Flashbots) to statistically increase the chance of minting an egg.

  • Use bots or scripts to brute force favorable conditions.


💥 Impact

  • Game Imbalance: Whales or bots can find significantly more eggs than regular users.

  • Denial of Service Risk: Repeated calls can congest the network or monopolize block space.

  • Economic Exploit: Users can unfairly collect more NFTs and potentially manipulate rewards or downstream mechanics (like the vault or egg utility).

  • Randomness Manipulation: Combined with predictable randomness, this opens the door to gaming the outcome.


🔧 Tools Used

  • Manual code review

  • Solidity best practices and anti-botting guidelines

  • Ethereum mempool transaction behavior analysis


✅ Recommendations

✅ Solution: Add Per-User Cooldown

Implement a per-user time-based rate limit to prevent rapid repeated calls.

Example:

mapping(address => uint256) public lastSearchTime;
uint256 public constant SEARCH_COOLDOWN = 30; // 30 seconds cooldown
function searchForEgg() external {
require(gameActive, "Game not active");
require(block.timestamp >= startTime, "Game not started yet");
require(block.timestamp <= endTime, "Game ended");
require(
block.timestamp - lastSearchTime[msg.sender] >= SEARCH_COOLDOWN,
"Search cooldown active"
);
lastSearchTime[msg.sender] = block.timestamp;
uint256 random = uint256(
keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender, eggCounter))
) % 100;
if (random < eggFindThreshold) {
eggCounter++;
eggsFound[msg.sender] += 1;
eggNFT.mintEgg(msg.sender, eggCounter);
emit EggFound(msg.sender, eggCounter, eggsFound[msg.sender]);
}
}

Optional Enhancements:

  • Make SEARCH_COOLDOWN adjustable by the owner within bounds.

  • Introduce a gas-based cost to discourage excessive searches.

  • Replace randomness with Chainlink VRF or a commit-reveal pattern to make brute forcing ineffective.


Updates

Lead Judging Commences

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

No rate limiting

Contract lacks any cooldown mechanism, search limits, or costs in the searchForEgg() function

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.