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:
FundCreate
The 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.
FundContribute
The 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.
FundWithdraw
This 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.