RustFund

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

Contribution Tracking Vulnerability: Permanent Fund Loss Risk

Summary

A critical vulnerability in the contribution tracking mechanism prevents contributors from receiving refunds and permanently locks their funds. Due to improper contribution amount tracking, the protocol's core promise of refundability is completely broken.

Vulnerability Details

1. Refund Mechanism Failure

Root Cause: Contributions are initialized and never updated with the actual contributed amount.

pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
let amount = ctx.accounts.contribution.amount; // Always 0!
// Critically: Will always transfer 0 SOL
}

Impact:

  • All refund attempts will return 0 SOL

  • Contributors cannot recover funds if a campaign fails

  • Complete breakdown of the refund promise

2. Contribution Tracking Mechanism

Flawed Implementation:

pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
if contribution.contributor == Pubkey::default() {
contribution.contributor = ctx.accounts.contributor.key();
contribution.fund = fund.key();
contribution.amount = 0; // Critical: Amount never updated
}
// SOL transfer happens
fund.amount_raised += amount; // Total raised tracked
// contribution.amount NOT incremented
}

Consequences:

  • Individual contribution amounts remain at 0

  • No per-contributor tracking

  • The total fund raised appears correct, masking the underlying issue

3. Systemic Protocol Violations

  • Broken Refund Promise: Contributors cannot reclaim funds

  • Data Integrity Compromised: Individual contribution records are meaningless

  • Financial Risk: Potential permanent loss of user funds

Impact Assessment

  • Severity: Critical

  • Financial Risk: High

  • User Trust: Severe damage to platform credibility

  • Potential Fund Loss: 100% of individual contributions at risk

Technical Analysis

Silent Failure Mechanism:

  • Transactions appear successful

  • fund.amount_raised reflects total contributions

  • Individual contribution records remain zeroed out

  • The refund function silently fails, transferring 0 SOL

Recommended Remediation

pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
// Existing initialization logic
// Critical fix: Update individual contribution amount
contribution.amount += amount;
// Maintain existing total raised tracking
fund.amount_raised += amount;
Ok(())
}
pub fn refund(ctx: Context<FundRefund>) -> Result<()> {
// Now uses the correctly tracked contribution amount
let amount = ctx.accounts.contribution.amount;
// Transfer actual contributed amount
transfer_sol(ctx.accounts.contributor, amount)?;
Ok(())
}

Mitigation Strategies

  1. Immediate Code Patch

    • Update contribute function to increment contribution.amount

    • Add comprehensive unit tests for contribution tracking

    • Implement robust refund mechanism validation

  2. Long-Term Recommendations

    • Conduct a full security audit of contribution tracking logic

    • Implement additional validation checks

    • Add logging and monitoring for contribution activities

Conclusion

This vulnerability represents a critical failure in the protocol's core financial mechanism. To prevent permanent user fund loss and restore platform integrity, immediate action is required.

Updates

Appeal created

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

Contribution amount is not updated

Support

FAQs

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