RustFund

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

Missing goal verification in refund function allows draining of successfully funded projects

Description

The rustfund::refund function only checks if the deadline has passed before allowing refunds, but it doesn't verify if the funding goal has been met. This contradicts the documented behavior in the README, which states: "Contributors can get refunds if deadlines are reached and goals aren't met." The current implementation allows contributors to withdraw funds from successfully funded projects after the deadline passes, potentially draining the fund.

This issue creates a critical mismatch between the expected behavior and the actual implementation, undermining the entire crowdfunding mechanism by allowing contributors to withdraw from successful campaigns.

Proof of Concept

  1. Creator creates a fund with a goal of 100 SOL and sets a deadline

  2. Contributors collectively contribute 120 SOL, exceeding the goal

  3. The deadline passes, making the campaign successful

  4. Despite meeting the goal, contributors can still call rustfund::refund to withdraw their contributions

  5. This allows draining of a successfully funded project, preventing the creator from accessing the promised funds

// Current implementation only checks deadline, not goal
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());
}
// Refund logic follows without checking if goal was met
// ...
}

Recommendation

Add goal verification to the refund function

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());
}
+
+ // Only allow refunds if goal wasn't met
+ if ctx.accounts.fund.amount_raised >= ctx.accounts.fund.goal {
+ return Err(ErrorCode::GoalReached.into());
+ }
// Existing refund logic
// ...
}

This approach adds a state machine to properly track the fund's status and enforces the correct refund rules based on both deadline and goal achievement.

Updates

Appeal created

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

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

Support

FAQs

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

Give us feedback!