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 8 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.

Give us feedback!