Eggstravaganza

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

Lack of interaction limits in `EggHuntGame::searchForEgg()` allows spam and automated exploitation

Description: The function EggHuntGame::searchForEgg() can be called unlimited times by any user without cooldown, rate limit, or cap per participant.

This design allows users or bots to spam the function in tight loops, increasing their chance of finding eggs through brute force rather than fair random discovery. While the NFTs currently have no stated economic value, this flaw undermines the fairness and competitive integrity of the game.

@> function searchForEgg() external {
require(gameActive, "Game not active");
require(block.timestamp >= startTime, "Game not started yet");
require(block.timestamp <= endTime, "Game ended");
// Pseudo-random number generation (for demonstration purposes only)
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]);
}
}

Impact:

  • Encourages botting and automation to gain an advantage.

  • Rewards those who can interact faster or more often.

  • Disincentivizes casual users who rely on “luck”.

  • May overload the contract if many users attempt spam at once.

Tools Used

Manual review, Foundry

Recommended Mitigation:

It is recommended to introduce a per-user cooldown mechanism using a mapping to track each user's last search attempt. This will prevent a player (or bot) from interacting repeatedly without restrictions.

+ uint256 public constant TEN_SECONDS = 10;
+ mapping(address => uint256) public lastSearch;
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 >= lastSearch[msg.sender] + TEN_SECONDS, "Wait before next search");
+ lastSearch[msg.sender] = block.timestamp;
// Pseudo-random number generation (for demonstration purposes only)
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]);
}
}
Updates

Lead Judging Commences

m3dython Lead Judge 3 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.