RustFund

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

Withdraw Function Allows Early Withdrawals Before Campaign Ends

Summary

The withdraw function currently allows the creator to withdraw funds at any time, even if the campaign has not yet reached its deadline or the funding goal. This behavior may contradict the intended logic of RustFund.

The documentation states:

"Creators can withdraw funds after successful campaigns."

This suggests that a campaign must be "successful" before withdrawal is possible. However, the current implementation does not enforce any deadline or goal checks, allowing fund creators to withdraw early, even if the campaign has not concluded.

Vulnerability Details

  • The withdraw function does not verify if the funding goal is met before allowing the creator to withdraw.

  • The function also does not check if the campaign has reached its deadline, meaning funds can be withdrawn mid-campaign.

  • This directly contradicts the documentation, which states that funds should only be withdrawn after a "successful" campaign.

  • If the campaign is supposed to follow a goal-based model, then allowing early withdrawals breaks the funding logic and reduces contributor trust.

Affected Code

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
**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(())
}

Issue in Code

  1. No check if the funding goal was met before allowing withdrawals.

  2. No check if the deadline has passed, meaning withdrawals can happen mid-campaign.

  3. Funds can be drained at any time, breaking contributor expectations.

Impact

  • Creators can withdraw funds early, even before reaching the goal.

  • Backers may lose trust, knowing creators can cash out mid-campaign without delivering results.

  • Potential fund misuse, where a creator starts a campaign, withdraws early, and abandons the project.

  • Contradicts RustFund’s intended funding model if it follows a goal-based system like Kickstarter.

Tools Used

Manual Code Review

Recommendations

To enforce goal-based withdrawals, the function should check:
1. If the campaign’s deadline has passed.
2. If the funding goal has been met.

Modify the function to only allow withdrawals if the campaign is successful:

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let fund = &ctx.accounts.fund;
// **Fix: Check if the deadline has passed**
if fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::CampaignStillActive.into());
}
// **Fix: Ensure the goal has been met**
if fund.amount_raised < fund.goal {
return Err(ErrorCode::GoalNotReached.into());
}
let amount = fund.amount_raised;
**fund.to_account_info().try_borrow_mut_lamports()? =
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(())
}
Updates

Appeal created

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

No deadline check in `withdraw` function

No goal achievement check in `withdraw` function

Support

FAQs

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