The "rustfund" contract has a design flaw where rent exemption lamports, paid during the creation of Fund and Contribution accounts, remain stuck in these accounts after their purpose is fulfilled. There is no mechanism to close these accounts or reclaim the remaining SOL, leaving small amounts (approximately 0.00089 SOL per account, based on Solana’s rent model) inaccessible. While the financial impact is minor, this inefficiency results in a permanent loss of resources, which is suboptimal for a production-ready contract and could accumulate costs in a widely used system.
The vulnerability stems from the lack of account closure functionality in the contract. In Solana, accounts created with the init instruction (e.g., Fund and Contribution accounts) require a minimum balance to be rent-exempt, paid by the creator or contributor. However, once the fund is withdrawn or contributions are refunded, these accounts persist with their rent exemption lamports, and no function exists to reclaim them.
The root cause is the absence of a "close account" instruction for Fund and Contribution accounts after their lifecycle ends. The contract initializes these accounts with specific space allocations but does not provide a way to deallocate them. Below are the relevant snippets:
FundCreateThe init attribute creates the fund account, with the creator paying the rent exemption (e.g., ~0.00089 SOL for a minimal account, more with Fund::INIT_SPACE).
After FundWithdraw transfers fund.amount_raised, the rent exemption lamports remain in the account.
FundContributeThe init_if_needed attribute creates the contribution account if it doesn’t exist, with the contributor paying the rent exemption.
After FundRefund resets contribution.amount to 0, the account persists with its rent exemption balance.
FundWithdrawThis transfers only fund.amount_raised, leaving the rent exemption lamports (initial balance minus amount_raised) in the fund account.
In Solana, accounts must maintain a minimum balance to avoid rent collection, and without a closure mechanism, these lamports are effectively locked.
The impact of this vulnerability is relatively low but notable:
Resource Loss: Each Fund and Contribution account retains its rent exemption lamports (e.g., ~0.00089 SOL for a small account, potentially more depending on INIT_SPACE). For a single campaign, this is negligible, but in a system with many funds or contributors, the cumulative loss could become significant.
Manual Code Review
To mitigate this vulnerability, the following steps are recommended:
Add a CloseFund Function:
Implement a new function to close the Fund account after withdrawal, transferring remaining lamports to the creator. Here’s an example:
The close = creator attribute transfers the remaining lamports to the creator and deallocates the fund account.
Call this after FundWithdraw to reclaim the rent exemption.
Add a CloseContribution Function:
Implement a function to close the Contribution account after a refund, transferring remaining lamports to the contributor:
The close = contributor attribute reclaims the lamports.
The check ensures the contribution is refunded first.
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.