A PDA is only as safe as the seeds and bump that define it. When auditing an Anchor program, check every account that is supposed to be a PDA.
Checks
- Constrain every PDA with
seedsandbump. Without the constraint, any account of the right type can be passed in its place. - Store the canonical bump at init and validate with
bump = vault.bump. This rules out non-canonical bumps and avoids recomputingfind_program_address. - Put the authority in the seeds of per-user accounts, so one user cannot pass another user's PDA.
- Avoid seed collisions. Adjacent variable-length seeds can concatenate to the
same bytes (
"ab" + "c"and"a" + "bc"). Use fixed prefixes or fixed-size seeds. - Check owners on unchecked accounts.
Account<T>verifies owner and discriminator;UncheckedAccountand rawAccountInfodo not.
rust
#[account(
mut,
seeds = [b"vault", authority.key().as_ref()],
bump = vault.bump,
has_one = authority,
)]
pub vault: Account<'info, Vault>,