withdraw(address target)
pays out the entire contract balance with Solidity’s transfer()
, which:
Forwards only 2 300 gas → reverts for most multisig / module wallets.
Has become fragile after EIP-1884; even EOAs wrapped in smart-accounts can fail.
Lacks target != address(0)
guard — ETH can be burned.
Result: Festival revenue can be stuck or burned, blocking withdrawals until a contract upgrade or redeploy.
Likelihood:
Organizers typically route funds to Gnosis Safes or payment-splitter contracts that need >2 300 gas → call reverts.
Impact:
ETH locked in FestivalPass
. Operational disruption during event. Potential permanent loss if zero address supplied.
The PoC spins up an ExpensiveReceiver
whose receive()
deliberately uses > 2 300 gas. When withdraw()
attempts to pay this address the call reverts, proving that the current transfer()
based implementation can lock funds.
Switching to a low-level call
forwards all remaining gas, checks success, and blocks the zero-address. This makes withdrawals compatible with multisigs and smart-account wallets and removes the 2 300 gas fragility.
Owner/admin is trusted / Zero address check - Informational
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.