Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Pass Reconfiguration Vulnerability

Root + Impact

Description


The configurePass function in FestivalPass.sol can be called multiple times for the same passId by the organizer, which resets the current supply counter (passSupply[passId] = 0) each time. This creates several critical issues:

function configurePass(
uint256 passId,
uint256 price,
uint256 maxSupply
) external onlyOrganizer {
require(passId == GENERAL_PASS || passId == VIP_PASS || passId == BACKSTAGE_PASS, "Invalid pass ID");
require(price > 0, "Price must be greater than 0");
require(maxSupply > 0, "Max supply must be greater than 0");
passPrice[passId] = price;
passMaxSupply[passId] = maxSupply;
@> passSupply[passId] = 0; // Reset current supply - VULNERABILITY
}

Risk

Likelihood:

The organizer might already have minted passes before, and he could make a mistake by calling configurePass again, which resets the supply counter to 0.

Impact:

  • If passes have already been minted and the organizer calls configurePass again, the supply counter resets to 0

    This allows minting beyond the originally intended maximum supply for example: If 50 VIP passes were already sold and organizer reconfigures, the counter resets, allowing another 50+ passes to be minted

  • Organizer can change prices after passes have been sold, potentially creating unfair pricing. Early buyers might pay higher prices, while later buyers benefit from reduced prices.

  • Could be used maliciously to oversell passes, leading to venue capacity issues and undermining the NFT's value proposition based on limited supply

Proof of Concept


The POC is simple, an organizer can call configurePass the first time, passing in required variables to configure for a specific ticket type. The organizer can make a mistake and call the configurePass again, thereby overriding what was set before. This can be used to create an infinite number of tickets.

// Initial configuration
configurePass(VIP_PASS, 1 ether, 100);
// 50 VIP passes are sold
// passSupply[VIP_PASS] = 50
// Organizer reconfigures (accidentally or maliciously)
configurePass(VIP_PASS, 0.5 ether, 200);
// passSupply[VIP_PASS] = 0 (RESET!)
// Now 200 more passes can be sold at half price
// Total possible supply: 250 passes instead of the intended 100

Recommended Mitigation


Implement the function to stop reconfiguration once it has been configured before. This ensures that the terms under which users purchase passes cannot be changed retroactively.

function configurePass(
uint256 passId,
uint256 price,
uint256 maxSupply
) external onlyOrganizer {
require(passId == GENERAL_PASS || passId == VIP_PASS || passId == BACKSTAGE_PASS, "Invalid pass ID");
require(price > 0, "Price must be greater than 0");
require(maxSupply > 0, "Max supply must be greater than 0");
+ require(passSupply[passId] == 0, "Cannot reconfigure after passes have been minted");
passPrice[passId] = price;
passMaxSupply[passId] = maxSupply;
- passSupply[passId] = 0;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

configurePass resets the current pass supply circumventing the max supply check

This is not acceptable as high because any attack vectors related to organizer trying to milk ETH from participants is voided by the fact that the organizer is trusted.

Support

FAQs

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