Rust Fund

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

Campaign deadline can be set to 0, disabling deadline checks

Root + Impact

Description

  • The program performs critical campaign status checks inside `contribute` and `refund` instructions using the campaign deadline.

  • The `set_deadline` instruction does not validate that the target deadline parameter is greater than the current blockchain timestamp or non-zero.

pub fn set_deadline(ctx: Context<FundSetDeadline>, deadline: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
if fund.dealine_set {
return Err(ErrorCode::DeadlineAlreadySet.into());
}
// @> Root Cause: Missing verification that deadline > Clock::get()?.unix_timestamp
fund.deadline = deadline;
Ok(())
}

Risk

Likelihood:

  • Creators calling set_deadline with a value of 0 or a past timestamp.

Impact:

  • If set to 0, deadline-based constraints in contribute are bypassed, allowing contributions to continue indefinitely.

  • If set to a past timestamp, the campaign is locked immediately, blocking further contributions and locking the funds.

Proof of Concept

#[test]
fn test_set_deadline_zero_vulnerability() {
setup_syscall_stubs();
let fund_key = Pubkey::new_unique();
let creator_key = Pubkey::new_unique();
let program_id = crate::ID;
let mut fund_lamports = 100_000_000;
let mut fund_data = vec![0u8; 8 + Fund::INIT_SPACE];
let mut creator_lamports = 1_000_000_000;
let mut creator_data = vec![];
let initial_fund_state = Fund {
name: "Test Fund".to_string(),
description: "Desc".to_string(),
goal: 500,
deadline: 100,
creator: creator_key,
amount_raised: 0,
dealine_set: false,
};
let mut writer = &mut fund_data[..];
initial_fund_state.try_serialize(&mut writer).unwrap();
let fund_info = AccountInfo::new(
&fund_key, false, true, &mut fund_lamports, &mut fund_data, &program_id, false, 0
);
let creator_info = AccountInfo::new(
&creator_key, true, true, &mut creator_lamports, &mut creator_data, &program_id, false, 0
);
let fund_acc_final: Account<Fund> = Account::try_from(&fund_info).unwrap();
let creator_sig: Signer = Signer::try_from(&creator_info).unwrap();
let mut accounts = FundSetDeadline {
fund: fund_acc_final,
creator: creator_sig,
};
let ctx = Context::new(
&program_id,
&mut accounts,
&[],
FundSetDeadlineBumps::default(),
);
// Act: Set deadline to 0 (which is an invalid deadline logically)
let res = crate::rustfund::set_deadline(ctx, 0);
// Assert: Succeeds because there is no validation preventing 0!
assert!(res.is_ok());
assert_eq!(accounts.fund.deadline, 0);
}

POC Explanation


The test initializes a mock Fund campaign and attempts to update its deadline to 0. The execution succeeds, which demonstrates that the instruction allows setting logical null/zero values as valid campaign deadlines.

Recommended Mitigation

pub fn set_deadline(ctx: Context<FundSetDeadline>, deadline: u64) -> Result<()> {
let fund = &mut ctx.accounts.fund;
if fund.dealine_set {
return Err(ErrorCode::DeadlineAlreadySet.into());
}
+ let current_time = Clock::get()?.unix_timestamp as u64;
+ require!(deadline > current_time, ErrorCode::InvalidDeadline);
fund.deadline = deadline;
Ok(())
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 1 day 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!