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 about 2 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.