Skip to main content
Sigvex

Critical Program ID Validation

Detects CPI calls to critical system programs without explicit address validation.

Critical Program ID Validation

Overview

Remediation Guide: How to Fix Critical Program ID Validation

The critical program ID validation detector identifies CPI calls to well-known system programs (System Program, SPL Token, Token-2022, the Metaplex Token Metadata program) without explicit address validation against known constants. These programs have fixed, published addresses that should always be hardcoded and verified before invocation. If an attacker can substitute a malicious program in place of a critical system program, they can intercept token transfers, steal funds, or corrupt on-chain state.

Why This Is an Issue

Critical system programs such as the System Program, SPL Token Program, and Token-2022 Program have fixed, well-known addresses. When a program makes a CPI to one of these targets using a variable program ID without first checking it against the expected constant, an attacker can supply a malicious program that masquerades as the system program. The malicious program receives the full account context and any PDA signing authority, enabling it to drain funds or manipulate state.

CWE mapping: CWE-20 (Improper Input Validation).

How to Resolve

Native Solana

use solana_program::pubkey::Pubkey;

const SYSTEM_PROGRAM_ID: Pubkey = solana_program::system_program::id();

pub fn process(accounts: &[AccountInfo]) -> ProgramResult {
    let system_program = &accounts[3];

    // Validate the program ID is the real System Program
    if system_program.key != &SYSTEM_PROGRAM_ID {
        return Err(ProgramError::IncorrectProgramId);
    }

    // Safe to invoke
    invoke(&create_account_ix, accounts)?;
    Ok(())
}

Anchor

#[derive(Accounts)]
pub struct Initialize<'info> {
    // Program<'info, System> validates the program ID at deserialization
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
}

Examples

Vulnerable Code

pub fn transfer_sol(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let system_program = &accounts[2]; // Not validated!

    let ix = solana_program::system_instruction::transfer(
        accounts[0].key,
        accounts[1].key,
        amount,
    );
    invoke(&ix, accounts)?; // Attacker can redirect to malicious program
    Ok(())
}

Fixed Code

pub fn transfer_sol(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
    let system_program = &accounts[2];

    if system_program.key != &solana_program::system_program::id() {
        return Err(ProgramError::IncorrectProgramId);
    }

    let ix = solana_program::system_instruction::transfer(
        accounts[0].key,
        accounts[1].key,
        amount,
    );
    invoke(&ix, accounts)?;
    Ok(())
}

Sample Sigvex Output

{
  "detector_id": "critical-program-id-validation",
  "severity": "critical",
  "confidence": 0.70,
  "description": "CPI is made to program v1 without validating the program ID against a known constant. If this is a critical system program, an attacker could substitute a malicious program to steal funds or corrupt state.",
  "location": { "function": "transfer_sol", "block": 0, "stmt": 1 }
}

Detection Methodology

The detector performs a two-pass analysis over the function’s HIR representation:

  1. Validation collection: Scans for CheckKey statements that compare account variables against constant values, building a set of validated program IDs.
  2. CPI analysis: Identifies all InvokeCpi operations and checks whether the program target is a hardcoded constant or a validated variable. Unvalidated variable-sourced CPI targets are flagged.
  3. Context adjustment: Confidence is reduced for Anchor programs (where Program<'info, T> validates automatically), admin functions, and read-only functions.

Limitations

  • The detector conservatively flags all unvalidated CPIs since it cannot determine the actual target program at static analysis time.
  • Validation performed in called functions or via indirect lookups is not tracked.
  • Programs that use an on-chain registry of trusted program IDs may produce false positives.

References