A crowdfunding lifecycle settles campaigns into a terminal state, validates the goal as a positive target, and reclaims rent from fully-settled accounts.
None of these exist: no CampaignStatus terminal state, no close instruction, no goal > 0 validation, no creator-exclusion in contribute(), and the two time guards use opposite strict comparisons — at deadline == now both contribute() and refund() pass simultaneously.
Likelihood:
Reason 1: The rent lock applies to 100% of campaigns ever created — deterministic, compounding dust per campaign.
Reason 2: goal = 0 and self-donation are trivial parameter choices available to any creator.
Impact:
Impact 1: SOL permanently locked as rent (~0.038 SOL per fund PDA for 5281 bytes + ~0.001 SOL per contribution PDA) — an unreclaimable protocol-level value leak.
Impact 2: goal = 0 plus self-contributions game any success gating (current or future) and let creators fake campaign momentum.
Three single calls — goal = 0 accepted, creator self-contributes, and no close instruction exists for drained PDAs:
Expected result: all three succeed — the zero-goal campaign exists, the self-contribution is recorded, and the drained PDAs remain rent-locked with no exit.
Introduce an explicit lifecycle: validate the goal at creation, track a terminal state per campaign, and add a close instruction that returns rent only after settlement — plus exclude the creator from contributing and settle one boundary semantics for the deadline second.
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.