PDA Path Confusion
Detects PDA derivations without program-specific namespace seeds, risking cross-program collisions.
PDA Path Confusion
Overview
Remediation Guide: How to Fix PDA Path Confusion
The PDA path confusion detector identifies PDA derivations that use only user-controlled seeds (account keys, parameters) without a program-specific namespace discriminator. Without a namespace, different programs using similar seed patterns can derive the same PDA address, enabling cross-program account confusion attacks.
Why This Is an Issue
PDAs are derived from seeds and a program ID. If two programs both derive PDAs using only [user_key] as seeds, they produce different addresses because the program IDs differ. However, a malicious program can intentionally mimic another program’s seed pattern, and without namespace discriminators, the derivation logic becomes ambiguous and harder to audit. More critically, if programs share the same program ID across upgrades or forks, namespace-less PDAs can collide.
CWE mapping: CWE-345 (Insufficient Verification of Data Authenticity).
How to Resolve
Native Solana
// VULNERABLE: only user-controlled seeds
let (pda, _) = Pubkey::find_program_address(&[user.key.as_ref()], program_id);
// FIXED: add program-specific namespace
let (pda, _) = Pubkey::find_program_address(
&[b"my-protocol-vault", user.key.as_ref()],
program_id,
);
Anchor
#[account(seeds = [b"vault", user.key().as_ref()], bump)]
pub vault: Account<'info, Vault>,
// The string literal b"vault" acts as a namespace discriminator
Examples
Vulnerable Code
pub fn init(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
// No namespace -- any program with same seed pattern could collide
let (escrow, bump) = Pubkey::find_program_address(
&[authority.key.as_ref(), mint.key.as_ref()],
program_id,
);
Ok(())
}
Fixed Code
pub fn init(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
// Namespace discriminator prevents cross-program collisions
let (escrow, bump) = Pubkey::find_program_address(
&[b"escrow-v1", authority.key.as_ref(), mint.key.as_ref()],
program_id,
);
Ok(())
}
Sample Sigvex Output
{
"detector_id": "pda-path-confusion",
"severity": "medium",
"confidence": 0.75,
"description": "PDA is derived using only user-controlled seeds without a program-specific namespace discriminator.",
"location": { "function": "init", "block": 0, "stmt": 0 }
}
Detection Methodology
- PDA syscall detection: Identifies
find_program_addressandcreate_program_addresscalls in assignments andinvoke_signedseeds. - Seed analysis: Classifies each seed component as namespace (constants, loads, program ID syscalls) or user-controlled (variables, parameters, account keys).
- Namespace check: Flags derivations that have user-controlled seeds but no namespace markers.
- Conservative classification: Constants and memory loads are treated as potential namespaces to avoid false positives.
Limitations
- Constants used as seeds are treated as namespaces, but small numeric constants may not provide meaningful namespacing.
- The detector cannot distinguish between a meaningful string discriminator and an arbitrary constant.
- PDA derivations in Anchor programs with
seedsconstraints are recognized at reduced confidence.
Related Detectors
- PDA Seed Collision — detects PDA seed collision vulnerabilities
- PDA Seed Validation — validates PDA seed derivation patterns