Summary
The user's contribute data account never actually records the contribution, so user funds are completely lost.
Vulnerability Details
The contribute
instruction initializes the contribution data account, but never increments the amount contributed to contribution.amount
. But the user's SOL contribution is still transferred to the fund. Since the user has no contribution recorded, they also can't withdraw their deposited balance, so user funds are completely lost.
We can see this in the instruction below:
pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
let contribution = &mut ctx.accounts.contribution;
if fund.deadline != 0 && fund.deadline < Clock::get().unwrap().unix_timestamp.try_into().unwrap() {
return Err(ErrorCode::DeadlineReached.into());
}
if contribution.contributor == Pubkey::default() {
contribution.contributor = ctx.accounts.contributor.key();
contribution.fund = fund.key();
contribution.amount = 0;
}
let cpi_context = CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.contributor.to_account_info(),
to: fund.to_account_info(),
},
);
system_program::transfer(cpi_context, amount)?;
fund.amount_raised += amount;
Ok(())
}
https://github.com/CodeHawks-Contests/2025-03-rustfund/blob/b5dd7b0ec01471667ae3a02520701aae405ac857/programs/rustfund/src/lib.rs#L25-L52
Impact
Total loss of user funds
Tools Used
Manual inspection
Recommendations
Add the following code to record user contributions:
pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
let contribution = &mut ctx.accounts.contribution;
@@ -36,6 +37,9 @@ pub mod rustfund {
contribution.fund = fund.key();
contribution.amount = 0;
}
+
+
+ contribution.amount += amount;
let cpi_context = CpiContext::new(
@@ -54,12 +58,12 @@ pub mod rustfund {