RustFund

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

Circular Dependency in PDA Validation for FundWithdraw Instruction

Summary

The FundWithdraw instruction in the program contains a circular dependency in its account validation logic. The fund account's PDA is derived using fund.name, but fund.name cannot be accessed until the fund account is loaded. This causes the validation to fail unless the PDA is explicitly passed in the transaction.


Vulnerability Details

The bug occurs in the #[derive(Accounts)] struct for FundWithdraw:

#[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>,
}

Root Cause

  • The seeds for the PDA derivation include fund.name.as_bytes().

  • However, fund.name is not accessible at the time of validation because the fund account has not yet been loaded.

  • This creates a circular dependency. The PDA derivation requires fund.name, but fund.name can only be accessed after the fund account is validated.

Behavior:

  • The validation works only if the PDA is explicitly passed in the transaction.

  • If the PDA is not passed, the validation fails because fund.name cannot be retrieved during the derivation process.


Impact

  • The FundWithdraw instruction will fail unless the PDA is explicitly passed in the transaction, limiting the program's flexibility and usability.

  • Developers and users may encounter unexpected errors when interacting with the program, leading to confusion and frustration.


Tools Used

  • Identified the circular dependency during code inspection.


Recommendations

To resolve this issue, pass the name as instruction to FundWithdraw struct and as a argument in withdraw function

Updates

Appeal created

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

[Invalid] Circular dependency

This is actually not valid, because PDA verification is happening after the account is loaded by Anchor. Also, since this is a `withdraw` function, the `Fund` account is already initialized and contains the name field. This is different from the initial account creation scenario (`FundCreate`) where you wouldn't have access to the data yet. In the `FundWithdraw` instruction the `fund.name` is used as part of the seeds and serves as an additional verification that the correct `Fund` account is used. The PDA verification works correctly because the `Fund` account already exists and contains the required `name` field when the function is called. If the account doesn't exist, it is expected that the function will not work. This can be easily tested using the tests from the repository.

bube Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

[Invalid] Circular dependency

This is actually not valid, because PDA verification is happening after the account is loaded by Anchor. Also, since this is a `withdraw` function, the `Fund` account is already initialized and contains the name field. This is different from the initial account creation scenario (`FundCreate`) where you wouldn't have access to the data yet. In the `FundWithdraw` instruction the `fund.name` is used as part of the seeds and serves as an additional verification that the correct `Fund` account is used. The PDA verification works correctly because the `Fund` account already exists and contains the required `name` field when the function is called. If the account doesn't exist, it is expected that the function will not work. This can be easily tested using the tests from the repository.

Support

FAQs

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