Audit Anchor programs for common vulnerabilities. Reentrancy, PDA collisions, missing signer checks, and pre-deploy security checklists.
Install
npx skillscat add x4484/solana-wingman/solana-security-auditor Install via the SkillsCat registry.
SKILL.md
Solana Security Auditor
Systematic security review skill for Solana/Anchor programs.
Audit Workflow
When asked to audit a program:
- Scope - Identify all instructions and accounts
- Access Control - Check signer/authority requirements
- Account Validation - Verify constraints and ownership
- PDA Safety - Review seeds and bump handling
- Arithmetic - Check for overflow/precision issues
- CPI Safety - Analyze cross-program invocations
- State Management - Review initialization and closing
Critical Checks
1. Missing Signer Checks
// ❌ VULNERABLE - No authority verification
pub fn admin_action(ctx: Context<AdminAction>) -> Result<()> {
// Anyone can call
}
// ✅ SAFE
#[derive(Accounts)]
pub struct AdminAction<'info> {
#[account(has_one = admin)]
pub config: Account<'info, Config>,
pub admin: Signer<'info>,
}2. Missing Owner Checks
// VULNERABLE - raw AccountInfo, no ownership check
/// CHECK: unchecked
pub user_data: UncheckedAccount<'info>,
// SAFE - Account<> verifies owner automatically
pub user_data: Account<'info, UserData>,3. PDA Seed Collisions
// VULNERABLE - generic prefix risks collisions
seeds = [b"vault", user.key().as_ref()]
// SAFER - unique prefix prevents cross-instruction collisions
seeds = [b"user_vault", user.key().as_ref()]
bump = vault.bump, // Store and reuse canonical bump4. Reinitialization
// RISKY - init_if_needed allows reinitialization of closed accounts
#[account(init_if_needed, payer = user, space = 8 + 64)]
pub data: Account<'info, Data>,
// SAFE - init prevents reinitialization entirely
#[account(init, payer = user, space = 8 + 64)]
pub data: Account<'info, Data>,5. Arithmetic Overflow
// VULNERABLE
let total = amount1 + amount2; // Can overflow
// SAFE
let total = amount1.checked_add(amount2).ok_or(ErrorCode::Overflow)?;Note: Anchor enables
overflow-checks = truein release builds by default,
so basic arithmetic (+,-,*) panics on overflow instead of wrapping.
However,checked_*is still preferred because panics produce unhelpful
error messages to users, while explicit error handling gives actionable context.
6. Closing Accounts Safely
// Anchor's close zeroes data and transfers lamports automatically
#[account(mut, close = recipient)]
pub data: Account<'info, Data>,
// REMAINING RISK: Within the same transaction, another instruction
// can refund lamports to "revive" the closed account.
// Anchor sets CLOSED_ACCOUNT_DISCRIMINATOR to mitigate this.7. Type Cosplay / Account Confusion
// ❌ VULNERABLE - Wrong account type accepted
pub vault: AccountInfo<'info>,
// ✅ SAFE - Strong typing
pub vault: Account<'info, Vault>,8. Arbitrary CPI
// VULNERABLE - Arbitrary program called
invoke(&ix, &accounts)?;
// SAFE - Verify program ID
require_keys_eq!(
ctx.accounts.token_program.key(),
spl_token::ID,
ErrorCode::InvalidProgram
);9. Remaining Lamports Attack (Account Revival)
// VULNERABLE - Closed account can be revived in same transaction
// if another instruction refunds its lamports before tx ends
#[account(mut, close = recipient)]
pub data: Account<'info, Data>,
// SAFER - Check discriminator on all account reads
// Anchor does this automatically with CLOSED_ACCOUNT_DISCRIMINATOR10. Account Reloading After CPI
// VULNERABLE - stale data after CPI
invoke(&transfer_ix, &accounts)?;
// vault_account still has old balance in memory!
let balance = vault_account.amount; // STALE
// SAFE - reload after CPI
invoke(&transfer_ix, &accounts)?;
ctx.accounts.vault_account.reload()?;
let balance = ctx.accounts.vault_account.amount; // FRESH11. Duplicate Account Passing
// VULNERABLE - same account passed for two params
pub fn transfer(ctx: Context<Transfer>) -> Result<()> {
// If source == destination, tokens appear from thin air
}
// SAFE - verify accounts are different
require_keys_neq!(
ctx.accounts.source.key(),
ctx.accounts.destination.key(),
ErrorCode::DuplicateAccounts
);12. Cross-Program Reentrancy
// Solana prevents recursive reentrancy (A calls A)
// But cross-program reentrancy is possible (A calls B calls A)
// Apply checks-effects-interactions pattern:
// 1. Validate all inputs (checks)
// 2. Update state (effects)
// 3. Make CPIs last (interactions)Pre-Deploy Checklist
- All instructions have appropriate signer checks
- All accounts validated with correct owner
- PDA seeds are unique and collision-resistant
- Bump seeds stored and reused (not recalculated)
- No arithmetic overflow possible (use checked_*)
- Accounts closed safely (close constraint used)
- CPI targets verified
- No reinitialization vulnerabilities (no unguarded init_if_needed)
- Closed accounts protected from revival (discriminator checked)
- Account data reloaded after CPIs that mutate state
- No duplicate account passing exploits (source != destination)
- Checks-effects-interactions pattern followed for CPI calls
- Error codes are descriptive
- Events emitted for important state changes
- Admin functions have timelock/multisig (if applicable)
- Upgrade authority handled appropriately
- Tests cover edge cases and attack vectors
Severity Levels
- CRITICAL - Direct fund loss, privilege escalation
- HIGH - Potential fund loss under specific conditions
- MEDIUM - Griefing, DoS, or economic issues
- LOW - Best practice violations, code quality
- INFO - Suggestions, optimizations
Output Format
When reporting findings:
## [SEVERITY] Finding Title
**Location:** `program/src/instructions/withdraw.rs:45`
**Description:** Brief explanation of the vulnerability
**Impact:** What an attacker could do
**Recommendation:** How to fix it
**Code:**
\`\`\`rust
// Before (vulnerable)
...
// After (fixed)
...
\`\`\`References
- Sealevel Attacks - Common vulnerability patterns (archived, still useful)
- Anchor Security
- Solana Security Best Practices
- Helius Security Guide
- Neodyme Audits - Real-world exploit writeups
Cross-References
../../knowledge/gotchas/historical-hacks.md- Real-world exploit case studies../../tools/security/pre-production-checklist.md- Full pre-deploy checklist