RustFund

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

Improper Access Control in Withdrawal Function

Summary

A critical vulnerability exists in the withdrawal mechanism where the function lacks proper access control, potentially allowing unauthorized parties to trigger fund transfers to the campaign creator.

Vulnerability Details

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
let amount = ctx.accounts.fund.amount_raised;
// Critical Vulnerability: No explicit caller verification
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.creator.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}
#[derive(Accounts)]
pub struct FundWithdraw<'info> {
#[account(
mut,
seeds = [fund.name.as_bytes(), creator.key().as_ref()],
bump,
has_one = creator
)]
pub fund: Account<'info, Fund>,
#[account(mut)]
pub creator: Signer<'info>,
pub system_program: Program<'info, System>,
}

Technical Analysis

  • Current implementation uses has_one = creator constraint

  • However, this does NOT guarantee that ONLY the creator can call the function

  • The function can potentially be invoked by any account

  • Funds will still be transferred to the correct creator

Impact

  • Unnecessary exposure of critical financial function

  • Violation of access control best practices

  • Any user can trigger the withdrawal process

Recommendation

  • Explicit creator verification

pub fn withdraw(ctx: Context<FundWithdraw>) -> Result<()> {
// Explicit creator verification
require!(
ctx.accounts.fund.creator == ctx.accounts.creator.key(),
ErrorCode::UnauthorizedWithdrawal
);
let amount = ctx.accounts.fund.amount_raised;
// Existing transfer logic
**ctx.accounts.fund.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.fund.to_account_info().lamports()
.checked_sub(amount)
.ok_or(ProgramError::InsufficientFunds)?;
**ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? =
ctx.accounts.creator.to_account_info().lamports()
.checked_add(amount)
.ok_or(ErrorCode::CalculationOverflow)?;
Ok(())
}
#[error_code]
pub enum ErrorCode {
UnauthorizedWithdrawal,
}

Tools Used

  • Manual Code Review

  • Static Code Analysis

Updates

Appeal created

bube Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[Invalid] Lack of access control in `withdraw` function

There are enough security checks in `withdraw` function. Anchor enforces that creator must sign the transaction. And the `has_one = creator` ensures that the fund’s creator matches the provided creator account.

Support

FAQs

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