← ClaudeAtlas

solana-anchorlisted

Detect bug classes specific to Solana / Anchor (Rust) programs — missing signer checks, missing account owner checks, account-confusion / type-cosplay without discriminator validation, unchecked AccountInfo, non-canonical PDA seeds/bumps & seed collisions, missing has_one/constraint, CPI to unverified programs, close-account lamport-drain & revival, sysvar spoofing, and arbitrary-account substitution. Activate on any `.rs` file with `use anchor_lang`, `#[program]`, `#[derive(Accounts)]`, `#[account]`, `Signer<'info>`, or `AccountInfo`.
iktok90-design/ai-smart-contract-auditor · ★ 36 · AI & Automation · score 80
Install: claude install-skill iktok90-design/ai-smart-contract-auditor
# Solana / Anchor (Rust) detection ## When this applies - Any `.rs` file importing `anchor_lang` (`use anchor_lang::prelude::*`) - Macros `#[program]`, `#[derive(Accounts)]`, `#[account]`, `#[instruction(...)]` - Account wrappers `Signer<'info>`, `Account<'info, T>`, `AccountInfo<'info>`, `UncheckedAccount`, `Program<'info, T>`, `Sysvar<'info, T>` - PDA derivation: `seeds = [...]`, `bump`, `find_program_address`, `create_program_address` - CPI: `CpiContext`, `invoke`, `invoke_signed`, `*_cpi` Solana has no implicit caller. Every authority, ownership, and identity invariant must be asserted explicitly in the account struct or handler. ## Detection patterns ### Missing signer check (CRITICAL) ```rust #[derive(Accounts)] pub struct Withdraw<'info> { pub authority: AccountInfo<'info>, // ← not Signer; nobody proves they're authority #[account(mut)] pub vault: Account<'info, Vault>, } ``` **Signal:** an "authority"/"owner"/"admin" account typed `AccountInfo`/`UncheckedAccount` instead of `Signer<'info>`, or a handler reading `ctx.accounts.x` without checking `x.is_signer`. Anyone passes the real authority's pubkey without their signature. ### Missing owner check / arbitrary account substitution (CRITICAL) ```rust let data = ctx.accounts.state.to_account_info(); let state = State::try_from_slice(&data.data.borrow())?; // ← no owner check ``` **Signal:** deserializing from a raw `AccountInfo`/`UncheckedAccount` without verifying `account.owner == program_id`, or