Rust Fund

AI First Flight #9
Beginner FriendlyRust
EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

Missing Contribution Amount Validation in Refund

Root + Impact

Description

  • Describe the normal behavior in one or more sentences
    The `refund` function does not validate that `contribution.amount > 0` before processing a refund. This means users who haven't contributed (or have already been refunded) can call the refund function, wasting compute units and potentially causing state inconsistencies.

  • Explain the specific issue or problem in one or more sentences
    The normal behavior should verify that the contributor has a non-zero contribution amount before processing a refund. The current implementation reads the amount but doesn't validate it.

```rust:66-88:programs/rustfund/src/lib.rs
pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
**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.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(())
}
```
If `amount` is 0, the function will still execute the lamport transfers (transferring 0), reset the contribution amount, and consume compute units unnecessarily.

Risk

Likelihood:

  • * This occurs when users who haven't contributed call refund

    * This occurs when users who were already refunded call refund again

    * Spam/DoS vector for wasting compute units

Impact:

  • * Unnecessary compute unit consumption

    * Potential for spam attacks

    * State inconsistencies if function is called with 0 amount

    * Wasted transaction fees for users

Proof of Concept

1. User creates contribution account but never contributes (amount = 0)
2. User calls `refund()` - function executes but transfers 0 SOL
3. Function resets `contribution.amount` to 0 (already 0)
4. Compute units wasted, no actual refund occurs

Recommended Mitigation

```diff
pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount;
+
+ // Validate contribution amount
+ if amount == 0 {
+ return Err(ErrorCode::NoContribution.into());
+ }
+
if ctx.accounts.fund.deadline != 0 && ctx.accounts.fund.deadline > Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineNotReached.into());
}
+
+ // Check if goal was not met
+ if ctx.accounts.fund.amount_raised >= ctx.accounts.fund.goal {
+ return Err(ErrorCode::GoalMet.into());
+ }
**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.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;
+ ctx.accounts.fund.amount_raised = ctx.accounts.fund.amount_raised
+ .checked_sub(amount)
+ .ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}
```
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 16 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!