Normal behavior: any airdrop token that is never claimed (or that becomes unclaimable due to a deployment misconfiguration) should be recoverable by the owner, so funds are never locked forever in the contract.
The issue: the contract has no function that moves the airdrop token out except claim() (per-eligible-user, proof-gated); claimFees() only withdraws ETH. Any USDC that is never claimed — or that becomes unclaimable (e.g. D2's wrong-token-address bug, D3's wrong-merkle-root bug) — can never leave the contract.
Reason 1 // USDC arrives in the contract at deployment (100 USDC funding) and only claim() can move it out.
Reason 2 // claim() is proof-gated per eligible user; any user who never claims (or any bug that bricks claims) strands the funds.
Impact 1 // Turns every claim-blocking bug (D2, D3) from "airdrop paused" into "100 USDC permanently lost".
Impact 2 // Even in normal operation, USDC of users who never claim is irrecoverable by the owner.
PoC verified: covered by the end-state assertions in the D2/D3 PoCs (balance remains locked, no code path exists to move it) — verified PASS. Any USDC remaining in the contract after all claims has no exit path.
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.