Beatland Festival

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

One-Time Festival Contract Lock Prevents Future Upgradability or Recovery

Root + Impact

Description:

The setFestivalContract(address _festival) function inside BeatToken.sol allows the owner to assign the festivalContract address but only once.

function setFestivalContract(address _festival) external onlyOwner {
require(festivalContract == address(0), "Festival contract already set");
festivalContract = _festival;
}

This means no mechanism exists to update, change, or recover the festival contract in case of a bug, compromised address, or redeployment.

// Root cause in the codebase with @> marks to highlight the relevant section

function setFestivalContract(address _festival) external onlyOwner {
@> require(festivalContract == address(0), "Festival contract already set"); <@
festivalContract = _festival;
}

Risk

Likelihood:

  • Once the function is called, the contract becomes rigid to changes—this is likely to occur immediately during deployment setup.

  • In real deployments, issues often arise due to integration bugs or security incidents that require the ability to reconfigure system components.

Impact:

  • Project becomes non-upgradable even in emergency scenarios.

  • Loss of control in case of vulnerabilities or logic bugs in the initially set festival contract.

  • Potential for full reward logic breakdown if festivalContract misbehaves or self-destructs.


Proof of Concept

// Scenario: Owner calls setFestivalContract with a wrong or untested address
beatToken.setFestivalContract(address(0x123...));
// Later tries to correct it
beatToken.setFestivalContract(address(0x456...));
// reverts with: "Festival contract already set"

Recommended Mitigation

- require(festivalContract == address(0), "Festival contract already set");
+ require(_festival != address(0), "Invalid address");
+ festivalContract = _festival;

And use a safer pattern like:

function updateFestivalContract(address _festival) external onlyOwner {
require(_festival != address(0), "Zero address not allowed");
festivalContract = _festival;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

`setFestivalContract` only callable once

This is intended. It's done like that because the festival contract requires beat token's address and vice versa.

Support

FAQs

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