Beatland Festival

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

Organizer can create extremely long performances with no duration validation

Description

Normal behavior: Performances should have reasonable durations (e.g., 1-4 hours) representing actual festival events with fair reward distribution.

Issue: The createPerformance() function has no validation on maximum duration. Organizers can create extremely long performances (tested: 365 days) that remain active indefinitely, creating unfair reward advantages and breaking the intended festival economics.

Root Cause

function createPerformance(
uint256 startTime,
uint256 duration, // @> No validation on maximum duration
uint256 reward
) external onlyOrganizer returns (uint256) {
require(startTime > block.timestamp, "Start time must be in the future");
require(duration > 0, "Duration must be greater than 0"); // @> Only checks > 0
// Set start/end times
performances[performanceCount] = Performance({
startTime: startTime,
endTime: startTime + duration, // @> Can result in extremely long end times
baseReward: reward
});
// ...
}

No upper bound validation allows creation of performances lasting months or years.

Risk

Likelihood:

  • Organizer can create long performances anytime without restrictions

  • No validation prevents unreasonable durations

Impact:

  • Unfair reward distribution: Some users get access to long-duration, high-reward performances

  • Economic imbalance: Extended performance windows favor certain participants

  • System abuse: Breaks intended festival timing and reward mechanics

Proof of Concept

function test_PerformanceTimingAttack() public {
// Buy pass for 3x multiplier
vm.startPrank(attacker);
festivalPass.buyPass{value: 1 ether}(3); // Backstage pass
vm.stopPrank();
// Create performance with 1-year duration
vm.startPrank(organizer);
uint256 perfId = festivalPass.createPerformance(
block.timestamp + 1 hours,
365 days, // 1 year duration!
1000e18 // High reward
);
vm.stopPrank();
// Attend performance and get massive reward
vm.warp(block.timestamp + 1 hours + 1);
vm.startPrank(attacker);
festivalPass.attendPerformance(perfId);
// Result: 3000 BEAT earned (1000 * 3x multiplier)
// Performance remains active for entire year
vm.warp(block.timestamp + 180 days); // 6 months later
assertTrue(festivalPass.isPerformanceActive(perfId));
}

Result: Performance remains active for 365 days, allowing extended reward access.

Recommended Mitigation

function createPerformance(
uint256 startTime,
uint256 duration,
uint256 reward
) external onlyOrganizer returns (uint256) {
require(startTime > block.timestamp, "Start time must be in the future");
require(duration > 0, "Duration must be greater than 0");
+ require(duration <= 24 hours, "Duration cannot exceed 24 hours");
// Set start/end times
performances[performanceCount] = Performance({
startTime: startTime,
endTime: startTime + duration,
baseReward: reward
});
// ...
}

This limits performances to reasonable durations (24 hours max) while maintaining flexibility for various event types.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!