Skip to content

Quasar accepts invalid PDA definitions with more than 16 seeds #84

@R4Y4N3

Description

@R4Y4N3

What happened?

Quasar accepts and SBF-builds a PDA definition with 17 seed expressions in
#[account(seeds = [...], bump)], even though:

  • Quasar's PDA docs say: "The Solana runtime enforces a maximum of 16 seeds per
    PDA (plus the bump seed, for 17 total)."
  • Solana's PDA docs and upstream constants limit PDAs to 16 seeds.
  • Upstream Solana exposes MAX_SEEDS = 16.

Expected behavior:

  • Quasar should reject #[account(seeds = [...])] at compile time when the
    number of seed expressions exceeds 16.

Actual behavior:

  • Quasar compiles and cargo build-sbf succeeds for a PDA with 17 seed
    expressions.

Why this matters:

  • At minimum, this is a framework validation bug because Quasar accepts an
    invalid PDA definition that exceeds Solana's documented/runtime limits.
  • This may also be safety-relevant, because Quasar's PDA helpers in
    lang/src/pda.rs use fixed-size stack arrays and their safety comments assume
    the seed count is already bounded.

Relevant references:

Relevant code paths:

  • derive layer only checks per-seed length, not total seed count:
    derive/src/accounts/fields.rs
  • PDA helper uses fixed 19-slot arrays and assumes bounded n:
    lang/src/pda.rs

Minimal reproduction

#![no_std]

use quasar_lang::prelude::*;

declare_id!("22222222222222222222222222222222222222222222");

#[account(discriminator = 1)]
pub struct OverflowPda {
    pub bump: u8,
}

#[derive(Accounts)]
pub struct TooManySeeds<'info> {
    pub payer: &'info mut Signer,
    #[account(
        init,
        payer = payer,
        seeds = [
            b"s00",
            b"s01",
            b"s02",
            b"s03",
            b"s04",
            b"s05",
            b"s06",
            b"s07",
            b"s08",
            b"s09",
            b"s10",
            b"s11",
            b"s12",
            b"s13",
            b"s14",
            b"s15",
            b"s16"
        ],
        bump
    )]
    pub state: &'info mut Account<OverflowPda>,
    pub system_program: &'info Program<System>,
}

#[program]
mod pda_too_many_seeds_poc {
    use super::*;

    #[instruction(discriminator = 1)]
    pub fn initialize(ctx: Ctx<TooManySeeds>) -> Result<(), ProgramError> {
        ctx.accounts.state.bump = ctx.bumps.state;
        Ok(())
    }
}


Commands used:


cargo check --manifest-path poc/pda-too-many-seeds/Cargo.toml
cargo build-sbf --manifest-path poc/pda-too-many-seeds/Cargo.toml


Both commands succeeded locally.

I also saved the local reproduction in this repo at:

- `poc/pda-too-many-seeds/src/lib.rs`
- `poc/pda-too-many-seeds/README.md`

Error output

There is no PDA-related compile error or build rejection.

Observed output ends with:


warning: `pda-too-many-seeds-poc` (lib) generated 2 warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s


and:


warning: `pda-too-many-seeds-poc` (lib) generated 2 warnings
Finished `release` profile [optimized] target(s) in 0.23s


The warnings are unrelated `unexpected cfg` warnings from macros, not seed
validation errors.

Quasar version

d39ed6a

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions