RustFund

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

Fund creator can withdraw funds before deadline

Description

The withdraw function in the RustFund program does not check if the deadline has passed before allowing the fund creator to withdraw all contributed funds. This is a serious security issue as it allows the fund creator to withdraw all contributions at any time, even if the funding period is still active.

Proof of Concept

  1. User A creates a fund using fund_create with a deadline 30 days in the future

  2. User B contributes 1 SOL to the fund using contribute

  3. User A immediately calls withdraw and receives all the contributed SOL

  4. User A can do this at any time, regardless of whether the deadline has passed or the funding goal has been met

Relevant Code Snippets

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(())
}

Unlike other functions in the contract, withdraw has no deadline checks:

// In contribute function - has deadline check
if fund.deadline != 0 && fund.deadline < Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineReached.into());
}
// In refund function - has deadline check
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}

Recommendation

Add deadline check

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let fund = &ctx.accounts.fund;
+
+ // Check if deadline has passed
+ if fund.deadline != 0 && fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
+ return Err(ErrorCode::DeadlineNotReached.into());
+ }
let amount = fund.amount_raised;
// Rest of the function...
}

This issue is high severity as it undermines the core purpose of a time-bound crowdfunding contract and allows fund creators to potentially defraud contributors by withdrawing funds before the campaign period is complete.

Updates

Appeal created

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

No deadline check in `withdraw` function

Support

FAQs

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