Solana Security

Solana Program Security: A Comprehensive Guide for Rust Developers

Kennedy OwiroJanuary 1, 202611 min read

Solana's account model is fundamentally different from Ethereum's. Instead of contracts with internal storage, Solana programs operate on accounts passed as instruction parameters. This creates unique security challenges: missing account validation, PDA seed manipulation, CPI authority escalation, and arbitrary account access. If you're coming from Solidity, these bugs will surprise you.

1. Account Validation: The #1 Solana Vulnerability

Solana programs receive accounts as function parameters. The program must verify that each account is the correct one — attackers can pass any account.

// VULNERABLE: No owner check on the token account
pub fn withdraw(ctx: Context) -> Result<()> {
    // Attacker passes their own token account as 'vault'
    let vault = &ctx.accounts.vault;
    transfer_tokens(vault, ctx.accounts.recipient, amount)?;
    Ok(())
}

// SECURE with Anchor: Automatic validation
#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        seeds = [b"vault", authority.key().as_ref()],
        bump,
        token::mint = mint,
        token::authority = vault_authority,
    )]
    pub vault: Account<'info, TokenAccount>,
    pub authority: Signer<'info>,
    pub mint: Account<'info, Mint>,
    /// CHECK: PDA authority
    #[account(seeds = [b"authority"], bump)]
    pub vault_authority: AccountInfo<'info>,
}

2. PDA Security

Program Derived Addresses (PDAs) are deterministic addresses owned by programs. Seeds must be carefully chosen to prevent collisions and manipulation.

  • ✅ Include user-specific data in PDA seeds to prevent cross-user access
  • ✅ Always verify bump seed to ensure canonical PDA
  • ✅ Use unique seed prefixes for different account types
  • ❌ Don't use predictable or user-controllable seeds without verification

3. Cross-Program Invocation (CPI) Risks

CPI lets one program call another. The danger: passing signer privileges to a malicious program, or calling the wrong program entirely.

// VULNERABLE: Not checking the program being invoked
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
    let cpi_program = next_account_info(accounts)?;
    // Attacker passes a malicious program!
    invoke(&instruction, &[account1, account2])?;
    Ok(())
}

// SECURE: Verify program ID
require_keys_eq!(cpi_program.key(), spl_token::ID, MyError::InvalidProgram);

4. Signer Verification

Every instruction that modifies user state must verify the appropriate signer. In Anchor, use the Signer type. In native Solana, check account.is_signer.

5. Integer Overflow in Rust

Rust panics on overflow in debug mode but wraps silently in release mode. Solana programs compile in release mode, so overflow checks are needed.

// VULNERABLE in release builds
let total = amount_a + amount_b;  // Can wrap silently

// SECURE
let total = amount_a.checked_add(amount_b)
    .ok_or(MyError::Overflow)?;

Common Anchor Pitfalls

  • Using AccountInfo instead of Account<'info, T> — bypasses deserialization checks
  • Missing has_one or constraint in account validation structs
  • Forgetting to check is_initialized on accounts
  • Not closing accounts properly — rent-exempt lamports remain

How Vultbase Audits Solana Programs

  1. cargo-audit — Checks for known vulnerabilities in Rust dependencies
  2. cargo-clippy — Catches common Rust antipatterns and potential bugs
  3. Semgrep — Custom rules for Solana-specific vulnerability patterns
  4. Pattern DB — 127 Solana-specific patterns covering account validation, PDA, CPI, and signer issues

Solana's account model is powerful but unforgiving. Submit your Solana program for a comprehensive security audit.

SolanaRustAnchorprogram securityPDACPIaccount validation
Share

Written by

Kennedy Owiro

Founder & CTO, Vultbase

14+ years building security and QA systems at scale. Background in fintech security and Web3 smart contract testing. Built Vultbase's Intelligence Engine with 1,200+ exploit patterns from $40B+ in historical DeFi losses.

Protect your protocol before launch.

Submit your smart contracts for automated security analysis powered by 1,200+ real exploit patterns.

Start Your Audit →