Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

User Can Bypass Cooldown by Attending Different Performances

Root + Impact

Description

The attendPerformance function is designed to allow a user to attend a performance only if a cooldown period has passed since their last check-in. This mechanism is intended to throttle repeated usage and prevent abuse of rewards or attendance-based mechanics.

Root cause

lastCheckIn[msg.sender] is shared across all performances but not updated until after the check, making it possible to call the function repeatedly with different performance IDs within the same cooldown window.

function attendPerformance(uint256 performanceId) external {
require(isPerformanceActive(performanceId), "Performance is not active");
require(hasPass(msg.sender), "Must own a pass");
require(!hasAttended[performanceId][msg.sender], "Already attended this performance"); //AFFECTED LINES
require(block.timestamp >= lastCheckIn[msg.sender] + COOLDOWN, "Cooldown period not met");//AFFECTED LINES
}

Risk

Likelihood:

This issue is likely to occur in any system where performances are frequent and rewards are significant.

Requires minimal technical knowledge — an attacker only needs to know how to call the attendPerformance function repeatedly with different performance IDs.

If cooldown is used as an anti-bot or spam protection, this vulnerability defeats its purpose.

Impact:

  • Users can bypass the intended cooldown by attending different performances back-to-back.

  • This undermines rate-limiting logic, which might be in place to control reward farming or prevent spam.

  • In systems where attending a performance grants tokens, NFTs, or other benefits, a user could abuse this flaw to claim unfair rewards in a short period.

  • Could lead to economic imbalance or unfair distribution of incentives in a live environment.

Proof of Concept

// Attacker script (simplified):
for (uint i = 0; i < N; i++) {
festival.attendPerformance(i); // Bypasses cooldown by using different IDs
}

Recommended Mitigation

- require(block.timestamp >= lastCheckIn[msg.sender] + COOLDOWN, "Cooldown period not met");
+ require(block.timestamp >= lastGlobalCheckIn[msg.sender] + COOLDOWN, "Cooldown period not met");
+ lastGlobalCheckIn[msg.sender] = block.timestamp;
Updates

Lead Judging Commences

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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