RustFund

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

Incorrect Refund Logic and Fund Depletion Vulnerability

Summary

The refund function contains critical logic flaws that prevent proper refunds and could allow a malicious user to drain the entire fund balance.

Vulnerability Details

There are multiple issues in the refund function:

  1. The function checks if the deadline hasn't been reached, but should actually check if either the deadline hasn't been reached OR if the fund goal has been met:

if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
  1. More critically, the function doesn't properly update the fund's amount_raised value after a refund, which means multiple users could refund the same funds:

// Fund amount_raised is never decreased
ctx.accounts.contribution.amount = 0;
  1. There's no check to ensure that the refund amount doesn't exceed the fund's current balance.

Impact

This vulnerability has severe consequences:

  1. It allows any contributor to potentially drain the entire fund balance by repeatedly calling the refund function

  2. It doesn't properly track refunds, which means the fund's accounting will be incorrect

  3. Later contributors might not be able to get their refunds if earlier contributors have already drained the fund

  4. The fund creator could lose access to legitimately raised funds

Tools Used

Manual code review

Recommendations

pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let fund = &mut ctx.accounts.fund;
let amount = ctx.accounts.contribution.amount;
// Check if refund criteria are met
if fund.deadline != 0 && fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
// Ensure amount is positive to prevent zero-amount refund attacks
if amount == 0 {
return Err(ErrorCode::InsufficientFunds.into());
}
// Update the fund's amount_raised first
fund.amount_raised = fund.amount_raised.checked_sub(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Transfer the lamports
fund.to_account_info().try_borrow_mut_lamports()? =
fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
ctx.accounts.contributor.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.contributor.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
// Reset contribution amount after refund
ctx.accounts.contribution.amount = 0;
Ok(())
}
Updates

Appeal created

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

There is no check for goal achievement in `refund` function

`amount_raised` not updated in `refund` function

Support

FAQs

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