The withdraw() function allows withdrawal of all ETH collected from pass sales, but it is protected by onlyOwner instead of onlyOrganizer:
solidity
The inline comment explicitly states "Organizer withdraws ETH", indicating the intended design is that the festival organizer — not the contract deployer/owner — should control fund withdrawal.
However, due to the use of onlyOwner (inherited from OpenZeppelin's Ownable2Step), only the contract owner (set at deployment and transferable via ownership functions) can call this function.
This creates a critical mismatch between documented intent and actual access control.
Medium severity: No immediate loss of funds, but significant centralization and operational risk.
Misaligned incentives and trust model:
The protocol distinguishes between owner (likely team/multisig) and organizer (event-specific entity).
Festival organizers expect to withdraw revenue from ticket sales.
Currently, they cannot — only the contract owner can.
Operational failure risk:
If ownership is not transferred to the organizer (or a shared multisig), the organizer has no access to earned funds.
If ownership is transferred, the team permanently loses control over emergency recovery.
Trust assumption violation: Users buying passes assume revenue goes to the event organizer, but funds are locked under a different role.
Documentation vs code discrepancy: Clear comment-code mismatch reduces auditability and increases likelihood of misuse.
While not a direct exploit, this is a serious design flaw in access control that can lead to locked funds or unintended centralization.
Simple scenario demonstrating the mismatch:
solidity
This test passes and shows the organizer cannot access funds despite the comment claiming they can.
Align the access control with the documented intent. Two clean options:
solidity
This matches the comment and design intent: the festival organizer controls revenue.
If the team intentionally wants the owner (not organizer) to control funds, then:
Remove or correct the misleading comment
Update all documentation to reflect that the contract owner withdraws funds
Recommendation: Go with Option 1 — it aligns with the role separation already present in the contract (setOrganizer, onlyOrganizer functions).
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.