After withdraw() transfers all raised funds and after refund() returns a contribution, the respective PDA accounts remain open. The rent-exempt SOL (~0.002 SOL per account) that keeps them alive is never returned to the creator or contributor.
Likelihood: Every withdraw() and refund() call leaves orphaned accounts. Campaigns with many contributors multiply the locked rent linearly.
Impact: For a campaign with 100 contributors, 100 contribution PDAs × ~0.002 SOL = ~0.2 SOL locked permanently, plus the fund PDA rent. Accounts serve no purpose after close but continue consuming chain storage and locking user SOL.
The grep returns only the function signatures — no close constraint, no realloc, no manual lamport drain. Both functions transfer tokens and return Ok(()) without closing their respective PDAs. Every completed withdrawal leaves the fund PDA alive; every refund leaves the contribution PDA alive, each locking ~0.002 SOL.
For a campaign with 100 contributors that fully refunds: 100 contribution PDAs × ~0.002 SOL = ~0.2 SOL locked, unreclaimable by anyone.
Use Anchor's close constraint to zero and reclaim the account's lamports on exit:
## Description neither the `withdraw()` nor `refund()` functions properly close their respective accounts after the funds have been transferred. This results in the rent amount (the SOL required to keep the account allocated on the Solana blockchain) remaining locked in these accounts indefinitely. ## Vulnerability Details In Solana, accounts must maintain a minimum balance to remain "rent-exempt", ensuring they aren't purged from the blockchain. When accounts are no longer needed, best practice is to close them and return this rent to the appropriate party (typically the account creator). The RustFund protocol currently lacks this account cleanup mechanism. - The withdrawal process in `withdraw()` transfers the raised funds from the fund account to the creator - Similarly, the refund process in `refund()` transfers the contribution amount back to the contributor and resets the contribution amount In both functions, the account data is updated, but the accounts themselves remain open, with their rent amount locked. After all funds have been withdrawn or refunded, these accounts serve no further purpose but continue to consume blockchain resources and lock up SOL. ### Proof of Concept 1. Alice creates a fund with a goal of 100 SOL, which requires 0.1 SOL as rent for the fund account. 2. The fund successfully raises 100 SOL from various contributors, each of whom also paid rent for their contribution accounts (approximately 0.05 SOL each). 3. Alice calls `withdraw()` to claim the 100 SOL raised funds, but the fund account itself is not closed. 4. The 0.1 SOL rent for the fund account remains locked in the account indefinitely. 5. Similarly, when contributors request refunds through the `refund()` function, their contribution accounts are updated but not closed. 6. The rent for all contribution accounts (e.g., 10 contributors × 0.05 SOL = 0.5 SOL) remains locked indefinitely. 7. Over time, as more funds are created and more contributions are made, the amount of permanently locked SOL grows. ## Impact - Economic Inefficiency, - Blockchain bloat, - Reduced user returns ## Recommendations Implement proper account closure in both the `withdraw()` and `refund()` 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.