Assists with Program Derived Address patterns, validates seed construction, bump handling, canonical bump usage, and cross-program PDA access
curl -s https://parity.cx/api/skills/pda-helper | shcopyYou are analyzing all Program Derived Address patterns in a Solana program. PDAs are the primary mechanism for deterministic account addressing on Solana, and their misuse is a leading source of critical vulnerabilities. This skill produces a complete PDA map and validates every derivation against known-safe patterns.
| Source | Path | Contains |
|--------|------|----------|
| Vulnerability Rules | programs/parity/src/context_engine.rs > VULNERABILITY_RULES | unvalidated-pda pattern with detection hints |
| Framework Patterns | programs/parity/src/context_engine.rs > ANCHOR_PATTERNS | Correct PDA derivation and account init patterns |
| Security Audit Skill | skills/security-audit/SKILL.md | PDA validation checks (Step 4) |
GitHub base URL: https://github.com/paritydotcx/Skills/blob/main/
Scan the entire program and catalog every PDA reference:
**In #[derive(Accounts)] structs:**
seeds = [...] constraintsbump and bump = account.field constraintsinit with seeds (PDA creation)In instruction handlers:
Pubkey::find_program_address callsPubkey::create_program_address callsinvoke_signed with signer seedsFor each PDA, record: account name, seed components (type and source), bump handling, referencing instructions, and whether it is used as a CPI signer.
Verify seeds are fully deterministic and not attacker-controlled.
Safe seeds: string literals (b"vault"), account public keys (.key().as_ref()), numeric IDs (.to_le_bytes()), program-controlled state.
Unsafe seeds: user-supplied strings without length validation, unbounded byte arrays.
// VULNERABLE: unbounded user input
seeds = [b"profile", user_input.as_bytes()]
// SECURE: deterministic, known-length key
seeds = [b"profile", user.key().as_ref()]Finding if violated: Severity Critical, Pattern unvalidated-pda.
Verify every PDA stores and reuses its canonical bump:
init: bump is stored in the account databump = account.bump reuses stored bump (avoids 1,500 CU re-derivation)// VULNERABLE: re-derives each time
seeds = [b"vault", authority.key().as_ref()], bump,
// SECURE: uses stored bump
seeds = [b"vault", authority.key().as_ref()], bump = vault.bump,Check for potential PDA collisions:
[b"ab", b"cd"] == [b"abcd"] without separatorIf PDAs are used as CPI signers:
// VULNERABLE: hardcoded bump
let seeds = &[b"authority", &[255u8]];
// SECURE: stored bump
let seeds = &[b"authority", &[ctx.accounts.auth_pda.bump]];For PDAs owned by other programs: verify owner validation, correct external program ID in derivation, and matching seed patterns.
| Severity | Penalty |
|----------|---------|
| Critical | -25 |
| High | -15 |
| Medium | -8 |
| Info | -3 |
{
"score": 70,
"pda_map": {
"vault": {
"seeds": ["\"vault\"", "authority.key()"],
"bump_handling": "stored_canonical",
"created_in": "initialize",
"accessed_in": ["deposit", "withdraw"],
"used_as_signer": false
}
},
"findings": [...],
"summary": "5 PDAs analyzed. 1 high (bump re-derivation). No collision risks."
}