configurePass() lets the organizer change pricing or limits for any pass collection.
Unfortunately it also zeroes the on-chain minted counter that the primary mint function relies on to enforce the cap:
The sales routine trusts passSupply[collectionId] to block over-minting:
After an event is live and hundreds of passes are already in circulation, the owner can call configurePass() again.
Because passSupply is set back to 0, every subsequent call to buyPass() thinks no tokens have been sold and happily mints up to the cap again, allowing the total supply to grow without bound.
This breaks scarcity, undermines resale value, and inflates any pass-based reward calculations.
Likelihood:
Whenever the organizer calls configurePass
for a pass that was already configured.
Impact:
Economic & reputational: existing pass-holders are diluted, secondary-market pricing collapses, and any “per-pass” perks (BEAT bonuses, backstage access, leaderboards) lose integrity.
Mint 10 general passes (counter now = 10).
configurePass(general, samePrice, 5) → passSupply = 0.
Call buyPass(general) five more times.
All succeed even though actual circulating supply is now 15 > cap.
Never touch passSupply inside configurator functions.
If the cap itself must be reduced, require newMaxSupply ≥ passSupply to avoid locking future sales.
Alternatively make passMaxSupply immutable after the first mint, and expose a separate “phase” mechanism for price changes.
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.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.