Rust Fund

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

name is used as a PDA seed but is allowed up to 200 bytes (#[max_len(200)]), exceeding Solana's 32 byte seed limit, so any campaign name longer than 32 bytes cannot create a fund

Root + Impact

Description

  • The fund PDA is derived from the campaign name, and Solana limits every PDA seed to at most 32 bytes, so the usable name length is capped at 32 bytes.

    The Fund.name field is declared #[max_len(200)], advertising names up to 200 bytes, while FundCreate derives the PDA from name.as_bytes(). Any name longer than 32 bytes makes the seed exceed the limit and fund_create fails at runtime.

#[account(init, payer = creator, space = 8 + Fund::INIT_SPACE,
@> seeds = [name.as_bytes(), creator.key().as_ref()], bump)] // name is a PDA seed
pub fund: Account<'info, Fund>,
pub struct Fund {
@> #[max_len(200)] // advertises up to 200 bytes, but a seed is capped at 32 bytes
pub name: String,
// ...
}

Risk

Likelihood:

  • When a creator chooses a campaign name longer than 32 bytes, fund_create reverts because the PDA seed exceeds Solana's 32 byte per-seed limit.

Impact:

  • Names between 33 and 200 bytes are accepted by the declared data layout but cannot be used to create a fund, so the feature is partly broken and the schema is misleading. No funds are at risk.

Proof of Concept

A 40 byte name cannot create a fund; the call reverts with "Max seed length exceeded".

it("a name longer than 32 bytes cannot create a fund", async () => {
const longName = "x".repeat(40); // > 32 bytes
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from(longName), creator.publicKey.toBuffer()], program.programId);
let reverted = false;
try {
await program.methods.fundCreate(longName, "d", new anchor.BN(1))
.accounts({ fund: pda, creator: creator.publicKey, systemProgram: SystemProgram.programId })
.signers([creator]).rpc();
} catch (e) { reverted = true; }
assert.isTrue(reverted);
});

Recommended Mitigation

Make the declared maximum match what is actually usable as a seed. Reducing max_len to 32 and validating the name keeps the schema honest, so a caller is never told a name is valid when it cannot create a fund. (If you instead want to keep arbitrarily long names, derive the PDA from a fixed-size hash of the name, for example seeds = [&hash(name.as_bytes()).to_bytes(), creator.key().as_ref()], so each seed stays within 32 bytes; use one approach or the other, not both.)

- #[max_len(200)]
+ #[max_len(32)]
pub name: String,
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 7 hours 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!