RustFund

First Flight #36
Beginner FriendlyRust
100 EXP
View results
Submission Details
Severity: medium
Invalid

M-05. Contribution Accepted at Deadline

M-05. Contribution Accepted at Deadline

Severity: Medium

Category: Time-Based Logic / Economic Integrity

Summary

The RustFund protocol fails to enforce a strict cutoff for contributions at the campaign deadline. A contribution submitted at the exact timestamp of the deadline is still accepted, violating the expected campaign rules and compromising funding logic.

Vulnerability Details

Root cause: Improper conditional check using > instead of >= when validating time in the contribute function.

Affected Component:

  • Function: contribute

  • Struct: Fund

  • File: lib.rs

How it manifests:

  • The current logic checks if the deadline has passed (Clock::get()?.unix_timestamp > fund.deadline)

  • This allows transactions submitted at the exact second of the deadline to go through

  • Protocol state becomes inconsistent, allowing post-deadline behavior during race conditions

Impact

  • Contributions can be accepted during or after the expiration moment

  • Opens potential for race conditions and fund accounting anomalies

  • Contributes to protocol unpredictability under heavy network load

Proof of Concept (PoC)

// Create fund
await program.methods
.fundCreate(FUND_NAME, "Testing edge case", new anchor.BN(LAMPORTS_PER_SOL))
.accounts({ fund, creator: creator.publicKey, systemProgram: SystemProgram.programId })
.signers([creator])
.rpc();
// Set deadline to now + 5 seconds
const deadlineTs = Math.floor(Date.now() / 1000) + 5;
await program.methods
.setDeadline(new anchor.BN(deadlineTs))
.accounts({ fund, creator: creator.publicKey })
.signers([creator])
.rpc();
// Wait until exactly the deadline
const waitTime = deadlineTs - Math.floor(Date.now() / 1000);
if (waitTime > 0) {
await new Promise((resolve) => setTimeout(resolve, waitTime * 1000));
}
// Attempt to contribute exactly at deadline
try {
await program.methods
.contribute(new anchor.BN(0.1 * LAMPORTS_PER_SOL))
.accounts({ fund, contributor: contributor.publicKey, contribution, systemProgram: SystemProgram.programId })
.signers([contributor])
.rpc();
console.log("Contribution accepted at deadline — vulnerability confirmed");
} catch (e) {
console.log("Contribution rejected at deadline:", e.message);
}
/* OUTPUT:
Fund created
Deadline set for ~5 seconds from now
Waiting 5s for deadline to hit...
Attempting to contribute exactly at deadline...
Contribution accepted at deadline — vulnerability confirmed
*/

Tools Used

  • Manual Review

  • Anchor Framework

  • JavaScript automation with setTimeout to simulate timing

Recommendations

Update time logic in contribute to reject contributions at or after the deadline:

- if current_time > fund.deadline {
+ if current_time >= fund.deadline {
return Err(ErrorCode::DeadlineReached.into());
}

This ensures clean cutoffs and prevents unpredictable post-deadline activity.

Updates

Appeal created

bube Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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