PDA Path Confusion Remediation
How to fix PDA derivations lacking program-specific namespace seeds.
PDA Path Confusion Remediation
Overview
Related Detector: PDA Path Confusion
PDA path confusion occurs when PDA derivations use only user-controlled seeds without a program-specific namespace. The fix is to include a constant string discriminator as the first seed component.
Recommended Fix
Before (Vulnerable)
let (pda, _) = find_program_address(&[user.key.as_ref()], program_id);
After (Fixed)
let (pda, _) = find_program_address(&[b"vault", user.key.as_ref()], program_id);
Alternative Mitigations
1. Version-qualified namespaces
Include a version identifier for forward compatibility:
let (pda, _) = find_program_address(&[b"vault-v2", user.key.as_ref()], program_id);
2. Program ID as seed for cross-program PDAs
let (pda, _) = find_program_address(
&[b"cross-ref", source_program.as_ref(), user.key.as_ref()],
target_program_id,
);
3. Account type discriminators
Use different prefixes for each account type:
let (user_pda, _) = find_program_address(&[b"user", user.key.as_ref()], pid);
let (vault_pda, _) = find_program_address(&[b"vault", user.key.as_ref()], pid);
let (config_pda, _) = find_program_address(&[b"config"], pid);
Common Mistakes
Mistake 1: Using only numeric prefixes
// WEAK: single byte does not prevent accidental collision
let (pda, _) = find_program_address(&[&[1u8], user.key.as_ref()], pid);
Use descriptive string literals instead of numeric constants.
Mistake 2: Using user-controlled data as the namespace
// WRONG: user-controlled data is not a namespace
let prefix = &instruction_data[0..8]; // Attacker-controlled
let (pda, _) = find_program_address(&[prefix, user.key.as_ref()], pid);