Skip to content
Back to skills

2495 Solana 688de5e9

ASecurity

In Solana, most program instructions modify state. **Exclude** view-only patterns: - Instructions that only read account data without `mut` references - Pure computation functions that don't write to accounts

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
businessrustgo

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 2495-solana_688de5e9 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2495 Solana 688de5e9?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2495 Solana 688de5e9
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2495-solana-688de5e9/badge)](https://www.skillsdirectory.com/skills/tools-only-2495-solana-688de5e9)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Solana Entry Point Detection

## Entry Point Identification (State-Changing Only)

In Solana, most program instructions modify state. **Exclude** view-only patterns:
- Instructions that only read account data without `mut` references
- Pure computation functions that don't write to accounts

### Native Solana Programs
```rust
// Single entrypoint macro
entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // Dispatch to handlers based on instruction_data
}
```

### Anchor Framework
```rust
#[program]
mod my_program {
    use super::*;

    // Each pub fn is an entry point
    pub fn initialize(ctx: Context<Initialize>) -> Result<()> { }
    pub fn transfer(ctx: Context<Transfer>, amount: u64) -> Result<()> { }
}
```

### Entry Point Detection Rules
| Pattern | Include? | Notes |
|---------|----------|-------|
| `entrypoint!(fn_name)` | **Yes** | Native program entry |
| `pub fn` inside `#[program]` mod with `mut` accounts | **Yes** | Anchor state-changing |
| `pub fn` inside `#[program]` mod (view-only) | No | Exclude if no `mut` accounts |
| Functions in `processor.rs` matching instruction enum | **Yes** | Native pattern |
| Internal helper functions | No | Not externally callable |

## Access Control Patterns

### Anchor Constraints
```rust
#[derive(Accounts)]
pub struct AdminOnly<'info> {
    #[account(mut)]
    pub admin: Signer<'info>,

    #[account(
        constraint = config.admin == admin.key() @ ErrorCode::Unauthorized
    )]
    pub config: Account<'info, Config>,
}
```

### Common Access Control Patterns
| Pattern | Classification |
|---------|----------------|
| `constraint = X.admin == signer.key()` | Admin |
| `constraint = X.owner == signer.key()` | Owner |
| `constraint = X.authority == signer.key()` | Authority (Admin-level) |
| `constraint = X.governance == signer.key()` | Governance |
| `constraint = X.guardian == signer.key()` | Guardian |
| `has_one = admin` | Admin |
| `has_one = owner` | Owner |
| `has_one = authority` | Authority |
| `Signer` account with no constraints | Review Required |

### Native Access Control
```rust
// Check signer
if !accounts[0].is_signer {
    return Err(ProgramError::MissingRequiredSignature);
}

// Check specific authority
if accounts[0].key != &expected_authority {
    return Err(ProgramError::InvalidAccountData);
}
```

### Access Control Macros (Anchor)
```rust
#[access_control(is_admin(&ctx))]
pub fn admin_function(ctx: Context<AdminAction>) -> Result<()> { }

fn is_admin(ctx: &Context<AdminAction>) -> Result<()> {
    require!(ctx.accounts.admin.key() == ADMIN_PUBKEY, Unauthorized);
    Ok(())
}
```

## Contract-Only Detection (CPI Patterns)

### Cross-Program Invocation Sources
```rust
// Functions expected to be called via CPI
pub fn on_token_transfer(ctx: Context<TokenCallback>, amount: u64) -> Result<()> {
    // Should verify calling program
    require!(
        ctx.accounts.calling_program.key() == expected_program::ID,
        ErrorCode::InvalidCaller
    );
}
```

### CPI Verification Patterns
```rust
// Verify CPI caller
let calling_program = ctx.accounts.calling_program.key();
require!(calling_program == &spl_token::ID, InvalidCaller);

// Check instruction sysvar for CPI
let ix = load_current_index_checked(&ctx.accounts.instruction_sysvar)?;
```

## Extraction Strategy

1. **Detect Framework**:
   - Check `Cargo.toml` for `anchor-lang` → Anchor
   - Check for `entrypoint!` macro → Native

2. **For Anchor**:
   - Find `#[program]` module
   - Extract all `pub fn` within it
   - Parse `#[derive(Accounts)]` structs for constraints

3. **For Native**:
   - Find instruction enum (usually in `instruction.rs`)
   - Map variants to handler functions in `processor.rs`
   - Check each handler for signer/authority checks

4. **Classify**:
   - No authority constraints → Public (Unrestricted)
   - `has_one`, `constraint` with authority → Role-based
   - CPI-only patterns → Contract-Only

## Solana-Specific Considerations

1. **Account Validation**: Access control often via account constraints, not function-level
2. **PDA Authority**: Program Derived Addresses can act as authorities
3. **Signer vs Authority**: `Signer` alone doesn't mean admin—check what the signer controls
4. **Instruction Data**: Native programs dispatch based on instruction discriminator

## Common Gotchas

1. **Initialize Patterns**: `is_initialized` checks—first caller may set authority
2. **Upgrade Authority**: Programs can be upgraded—check upgrade authority
3. **Multisig**: Some operations require multiple signers
4. **CPI Safety**: Functions callable via CPI should verify calling program
5. **Freeze Authority**: Token accounts may have freeze authority

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.