Solana Security Auditing
Systematic security review framework for Solana programs, supporting both Anchor and native Rust implementations.
Review Process
Follow this systematic 5-step process for comprehensive security audits:
Step 1: Initial Assessment
Understand the program's context and structure:
- Framework: Anchor vs Native Rust (check for
use anchor_lang::prelude::*) - Anchor version: Check
Cargo.tomlfor compatibility and known issues - Dependencies: Oracles (Pyth, Switchboard), external programs, token programs
- Program structure: Count instructions, identify account types, analyze state management
- Complexity: Lines of code, instruction count, PDA patterns
- Purpose: DeFi, NFT, governance, gaming, etc.
Step 2: Systematic Security Review
For each instruction, perform security checks in this order:
- Account Validation - Verify signer, owner, writable, and initialization checks
- Arithmetic Safety - Check all math operations use
checked_*methods - PDA Security - Validate canonical bumps and seed uniqueness
- CPI Security - Ensure cross-program invocations validate target programs
- Oracle/External Data - Verify price staleness and oracle status checks
β See references/security-checklists.md for detailed checklists
Step 3: Vulnerability Pattern Detection
Scan for common vulnerability patterns:
- Type cosplay attacks
- Account reloading issues
- Improper account closing
- Missing lamports checks
- PDA substitution attacks
- Arbitrary CPI vulnerabilities
- Missing ownership validation
- Integer overflow/underflow
β See references/vulnerability-patterns.md for code examples and exploit scenarios
Step 4: Architecture and Testing Review
Evaluate overall design quality:
- PDA design patterns and collision prevention
- Account space allocation and rent exemption
- Error handling approach and coverage
- Event emission for critical state changes
- Compute budget optimization
- Test coverage (unit, integration, fuzz)
- Upgrade strategy and authority management
Step 5: Generate Security Report
Provide findings using this structure:
Severity Levels:
- π΄ Critical: Funds can be stolen/lost, protocol completely broken
- π High: Protocol can be disrupted, partial fund loss possible
- π‘ Medium: Suboptimal behavior, edge cases, griefing attacks
- π΅ Low: Code quality, gas optimization, best practices
- π‘ Informational: Recommendations, improvements, documentation
Finding Format:
## π΄ [CRITICAL] Title
**Location:** `programs/vault/src/lib.rs:45-52`
**Issue:**
Brief description of the vulnerability
**Vulnerable Code:**
```rust
// Show the problematic code
Exploit Scenario: Step-by-step explanation of how this can be exploited
Recommendation:
// Show the secure alternative
References:
- [Link to relevant documentation or similar exploits]
**Report Summary:**
- Total findings by severity
- Critical issues first (prioritize by risk)
- Quick wins (easy fixes with high impact)
- Recommendations for testing improvements
## Quick Reference
### Essential Checks (Every Instruction)
**Anchor:**
```rust
// β
Account validation with constraints
#[derive(Accounts)]
pub struct SecureInstruction<'info> {
#[account(
mut,
has_one = authority, // Relationship check
seeds = [b"vault", user.key().as_ref()],
bump, // Canonical bump
)]
pub vault: Account<'info, Vault>,
pub authority: Signer<'info>, // Signer required
pub token_program: Program<'info, Token>, // Program validation
}
// β
Checked arithmetic
let total = balance.checked_add(amount)
.ok_or(ErrorCode::Overflow)?;
Native Rust:
// β
Manual account validation
if !authority.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
if vault.owner != program_id {
return Err(ProgramError::IllegalOwner);
}
// β
Checked arithmetic
let total = balance.checked_add(amount)
.ok_or(ProgramError::ArithmeticOverflow)?;
Critical Anti-Patterns
β Never Do:
- Use
saturating_*arithmetic methods (hide errors) - Use
unwrap()orexpect()in production code - Use
init_if_neededwithout additional checks - Skip signer validation ("they wouldn't call this...")
- Use unchecked arithmetic operations
- Allow arbitrary CPI targets
- Forget to reload accounts after mutations
β Always Do:
- Use
checked_*arithmetic (checked_add,checked_sub, etc.) - Use
ok_or(error)?for Option unwrapping - Use explicit
initwith proper validation - Require
Signer<'info>oris_signerchecks - Use
Program<'info, T>for CPI program validation - Reload accounts after external calls that mutate state
- Validate account ownership, discriminators, and relationships
Framework-Specific Patterns
Anchor Security Patterns
β See references/anchor-security.md for:
- Account constraint best practices
- Common Anchor-specific vulnerabilities
- Secure CPI patterns with
CpiContext - Event emission and monitoring
- Custom error handling
Native Rust Security Patterns
β See references/native-security.md for:
- Manual account validation patterns
- Secure PDA derivation and signing
- Low-level CPI security
- Account discriminator patterns
- Rent exemption validation
Modern Practices (2025)
- Use Anchor 0.30+ for latest security features
- Implement Token-2022 with proper extension handling
- Use
InitSpacederive for automatic space calculation - Emit events for all critical state changes
- Write fuzz tests with Trident framework
- Document invariants in code comments
- Follow progressive roadmap: Dev β Audit β Testnet β Audit β Mainnet
Security Fundamentals
β See references/security-fundamentals.md for:
- Security mindset and threat modeling
- Core validation patterns (signers, owners, mutability)
- Input validation best practices
- State management security
- Arithmetic safety
- Re-entrancy considerations
Common Vulnerabilities
β See references/vulnerability-patterns.md for:
- Missing signer validation
- Integer overflow/underflow
- PDA substitution attacks
- Account confusion
- Arbitrary CPI
- Type cosplay
- Improper account closing
- Precision loss in calculations
Each vulnerability includes:
- β Vulnerable code example
- π₯ Exploit scenario
- β Secure alternative
- π References
Security Checklists
β See references/security-checklists.md for:
- Account validation checklist
- Arithmetic safety checklist
- PDA and account security checklist
- CPI security checklist
- Oracle and external data checklist
- Token integration checklist
Known Issues and Caveats
β See references/caveats.md for:
- Solana-specific quirks and gotchas
- Anchor framework limitations
- Testing blind spots
- Common misconceptions
- Version-specific issues
Security Resources
β See references/resources.md for:
- Official security documentation
- Security courses and tutorials
- Vulnerability databases
- Audit report examples
- Security tools (Trident, fuzzers)
- Security firms and auditors
Key Questions for Every Audit
Always verify these critical security properties:
-
Can an attacker substitute accounts?
- PDA validation, program ID checks, has_one constraints
-
Can arithmetic overflow or underflow?
- All math uses checked operations, division by zero protected
-
Are all accounts properly validated?
- Owner, signer, writable, initialized checks present
-
Can the program be drained?
- Authorization checks, reentrancy protection, account confusion prevention
-
What happens in edge cases?
- Zero amounts, max values, closed accounts, expired data
-
Are external dependencies safe?
- Oracle validation (staleness, status), CPI targets verified, token program checks
Audit Workflow
Before Starting
- Understand the protocol purpose and mechanics
- Review documentation and specifications
- Set up local development environment
- Run existing tests and check coverage
During Audit
- Follow the 5-step review process systematically
- Document findings with severity and remediation
- Create proof-of-concept exploits for critical issues
- Test fixes and verify they work
After Audit
- Present findings clearly prioritized by severity
- Provide actionable remediation steps
- Re-audit after fixes are implemented
- Document lessons learned for the protocol
Testing for Security
Beyond code review, validate security through testing:
- Unit tests: Test each instruction's edge cases
- Integration tests: Test cross-instruction interactions
- Fuzz testing: Use Trident to discover unexpected behaviors
- Exploit scenarios: Write POCs for found vulnerabilities
- Upgrade testing: Verify migration paths are secure
Core Principle
In Solana's account model, attackers can pass arbitrary accounts to any instruction.
Security requires explicitly validating:
- β Every account's ownership
- β Every account's type (discriminator)
- β Every account's relationships
- β Every account's state
- β Every signer requirement
- β Every arithmetic operation
- β Every external call
There are no implicit guarantees. Validate everything, trust nothing.