RustFund

First Flight #36
Beginner FriendlyRust
100 EXP
View results
Submission Details
Severity: high
Valid

`withdraw` without check the crowdfunding status

Summary

The withdraw function can be called at any time, without checking whether the crowdfunding is finished or the funding goal is met. This allows the creator to withdraw funds early, which may trap later contributors’ money.

Vulnerability Details

In the current implementation, the withdraw function directly calculates the withdrawal amount using let amount = ctx.accounts.fund.amount_raised, Then it transfers this amount from the fund to the creator — without any checks, no check for whether the deadline has passed, and no check for whether the goal has been reached.

That means the creator can withdraw before the campaign ends, even when the raised amount is below the goal.

Now imagine someone contributes after the creator has already withdrawn funds. Because amount_raised wasn’t updated, the contract still thinks there’s more money than there actually is. If the fund’s real balance is lower than amount_raised, the refund will fail — and the user’s money gets stuck in the contract.

Impact

If the creator withdraws early and amount_raised is not updated properly, later contributors might not be able to get their money back. Since the contract believes there’s more money than there actually is, refund attempts can fail — leaving users’ funds permanently stuck in the contract.

Tools Used

Manual review

Recommendations

Add proper checks in the withdraw function to make sure the funding goal has been reached and that the amount_raised hasn’t already been withdrawn or emptied.

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
+ if amount < ctx.accounts.fund.goal {
+ return Err(ErrorCode::GoalNotReached.into());
+ }
+ ctx.accounts.fund.amount_raised = 0;
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.creator.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}
#[error_code]
pub enum ErrorCode {
#[msg("Deadline already set")]
DeadlineAlreadySet,
#[msg("Deadline reached")]
DeadlineReached,
#[msg("Deadline not reached")]
DeadlineNotReached,
#[msg("Unauthorized access")]
UnauthorizedAccess,
#[msg("Calculation overflow occurred")]
CalculationOverflow,
+ #[msg("Goal not reached")]
+ GoalNotReached,
}
Updates

Appeal created

bube Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

No goal achievement check in `withdraw` function

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.