PDA System Collision
Detects PDA derivations with weak entropy that could collide with system program addresses.
PDA System Collision
Overview
Remediation Guide: How to Fix PDA System Collision
The PDA system collision detector identifies PDA derivations with weak seed entropy that could potentially collide with known system program addresses (System Program, Token Program, Token-2022, Associated Token Program, Memo Program, BPF Loader, Metaplex). While collisions are mathematically unlikely in a 256-bit address space, weak seed patterns combined with maliciously crafted program IDs could intentionally target specific addresses.
The detector flags three escalating patterns:
- Single constant seed: Minimal entropy, entirely deterministic based on program ID (Critical).
- Weak entropy seeds: Single variable or parameter seeds without discriminators (High).
- Missing canonical bump:
create_program_addresscalled without bump seed fromfind_program_address(Medium).
Why This Is an Issue
A PDA derived from a single constant or a single user-provided value has extremely low entropy. An attacker could craft a program ID that, combined with the weak seed, produces a PDA matching a system program address. This could bypass program ID validation checks that verify the account key but not the owner, enabling impersonation of system programs in CPI contexts.
CWE mapping: CWE-330 (Use of Insufficiently Random Values).
How to Resolve
Native Solana
// VULNERABLE: single constant seed
let pda = create_program_address(&[&[0]], program_id)?;
// FIXED: multiple seeds with discriminator and bump
let (pda, bump) = find_program_address(&[b"vault", user.key.as_ref()], program_id);
let pda = create_program_address(&[b"vault", user.key.as_ref(), &[bump]], program_id)?;
Anchor
#[account(seeds = [b"vault", user.key().as_ref()], bump)]
pub vault: Account<'info, Vault>,
Examples
Vulnerable Code
pub fn init(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
// Single constant -- Critical: entirely program-ID dependent
let pda = Pubkey::create_program_address(&[&[42]], program_id)?;
Ok(())
}
Fixed Code
pub fn init(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
let (pda, bump) = Pubkey::find_program_address(
&[b"vault", user.key.as_ref(), mint.key.as_ref()],
program_id,
);
Ok(())
}
Sample Sigvex Output
{
"detector_id": "pda-system-collision",
"severity": "critical",
"confidence": 0.78,
"description": "PDA derivation uses only a single constant value as seed. This provides minimal entropy and makes the derivation entirely deterministic based on program ID.",
"location": { "function": "init", "block": 0, "stmt": 0 }
}
Detection Methodology
- PDA detection: Identifies
find_program_addressandcreate_program_addresssyscalls. - Entropy analysis: Classifies seed strength by counting components and their types (constants, variables, parameters, loads).
- Single-constant detection: Flags seeds that consist of only one constant value as critical.
- Bump seed check: For
create_program_address, checks whether a bump seed is likely present. - System address awareness: Reports against the list of known critical system addresses.
Limitations
- The detector cannot actually verify whether a collision with a system address is mathematically possible for a given seed pattern.
- Entropy analysis is heuristic; complex seed expressions may be under- or over-counted.
- The bump seed check is conservative and may flag legitimate
create_program_addresscalls that include bump seeds in complex expressions.
Related Detectors
- Weak PDA Entropy — detects low-entropy seed sources
- PDA Path Confusion — detects missing namespace in PDA seeds