The "rustfund" contains a critical vulnerability in the FundWithdraw
function, allowing the creator to withdraw all raised funds (fund.amount_raised
) at any time without restrictions. There are no checks to ensure the crowdfunding goal (fund.goal
) has been met or that the deadline (fund.deadline
) has passed before withdrawal is permitted. This unrestricted access enables the creator to drain the fund account prematurely, potentially scamming contributors by withdrawing funds before the campaign concludes or succeeds. This behavior deviates from standard crowdfunding practices, where withdrawals are typically conditional on meeting predefined criteria, undermining the contract’s integrity and contributor trust.
The vulnerability is located in the FundWithdraw
function, which facilitates the transfer of all accumulated funds from the fund account to the creator’s account. The function lacks any conditional logic to verify that the crowdfunding campaign has met its goal or reached its deadline, allowing immediate and unconditional withdrawal.
The root cause is the absence of validation checks in FundWithdraw
to enforce crowdfunding rules. The function simply transfers the entire fund.amount_raised
to the creator without evaluating fund.goal
or fund.deadline
. Below is the relevant code snippet:
In this snippet:
amount
is set to fund.amount_raised
, representing all funds contributed to the campaign.
The SOL transfer occurs directly from the fund account to the creator’s account using low-level lamports manipulation.
There are no conditions checking fund.amount_raised >= fund.goal
or fund.deadline <= current_time
, which are standard in crowdfunding contracts to ensure fairness.
The Fund
struct defines goal
and deadline
fields, suggesting an intent to enforce a crowdfunding model where funds are only accessible to the creator if the campaign succeeds:
However, FundWithdraw
ignores these fields, allowing the creator to bypass the intended logic and withdraw funds at any point, even immediately after contributions begin.
This vulnerability has a profound impact on the contract’s security and reliability:
Potential for Scams: The creator can withdraw all funds at any time, even if the goal is far from being met or the deadline hasn’t passed. For example, if a fund has a goal of 100 SOL and only 10 SOL is raised, the creator can still take the 10 SOL, leaving contributors with no recourse until the deadline (and even then, refunds fail due to the first vulnerability).
Financial Loss for Contributors: Contributors cannot recover their funds after an early withdrawal, as the fund account would be drained, leaving insufficient lamports for refunds.
Manual Code Review
To mitigate this vulnerability, the following steps are recommended:
Add Goal and Deadline Checks in FundWithdraw
:
Modify the FundWithdraw
function to restrict withdrawals to cases where the crowdfunding goal is met and, optionally, the deadline has passed. Here’s the corrected code snippet:
fund.amount_raised < fund.goal
ensures the campaign has succeeded before funds can be withdrawn.
The optional deadline check (fund.deadline > current_time
) prevents early withdrawals, aligning with a time-bound campaign model. If the intent is to allow withdrawals anytime after the goal is met, this check can be omitted.
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.