Skip to main content
Sigvex

Hardcoded System Program Address

Detects hardcoded system program addresses instead of using named constants for program IDs.

Hardcoded System Program Address

Overview

Remediation Guide: How to Fix Hardcoded System Program Addresses

The hardcoded system program address detector identifies Solana programs that validate system program IDs (System Program, Token Program, Token-2022 Program, Associated Token Program, Memo Program, BPF Loader Upgradeable, canonical NFT metadata) against hardcoded byte arrays instead of using named constants. While the hardcoded addresses are functionally correct (system program addresses are immutable), using named constants improves code readability, prevents copy-paste errors, and follows Solana development best practices.

Sigvex scans CheckKey statements for constants that match known system program address bytes. Matches generate low-severity findings recommending the corresponding named constant. CWE mapping: CWE-1188 (Insecure Default Initialization of Resource).

Why This Is an Issue

This is a code quality issue rather than a security vulnerability:

  • Readability: system_program::id() or spl_token::id() communicates intent clearly; a 32-byte array does not.
  • Copy-paste risk: System program addresses are 32-byte arrays that differ by only a few bytes. Copying the wrong one produces a validation check against the wrong program, which is a real security bug.
  • Cross-program compatibility: Programs that interact with Token-2022 or multiple program versions benefit from using the canonical constants, which are updated with SDK releases.
  • Audit efficiency: Auditors reviewing code can quickly verify program ID constants but must manually decode byte arrays.

How to Resolve

Native Rust

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, system_program};

pub fn validate_system_program(accounts: &[AccountInfo]) -> ProgramResult {
    let sys_program = &accounts[0];

    // Instead of: if *sys_program.key != Pubkey::from([0, 0, 0, ...]) {
    if *sys_program.key != system_program::id() {
        return Err(ProgramError::IncorrectProgramId);
    }
    Ok(())
}

Anchor

#[derive(Accounts)]
pub struct CreateAccount<'info> {
    pub system_program: Program<'info, System>, // Validates automatically
    pub token_program: Program<'info, Token>,   // Validates automatically
}

Examples

Vulnerable Code

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

const TOKEN_PROGRAM: [u8; 32] = [
    6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172,
    28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169,
];

pub fn validate_token(accounts: &[AccountInfo]) -> ProgramResult {
    if *accounts[0].key != Pubkey::from(TOKEN_PROGRAM) {
        return Err(ProgramError::IncorrectProgramId);
    }
    Ok(())
}

Fixed Code

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult};

pub fn validate_token(accounts: &[AccountInfo]) -> ProgramResult {
    if *accounts[0].key != spl_token::id() {
        return Err(ProgramError::IncorrectProgramId);
    }
    Ok(())
}

Sample Sigvex Output

{
  "detector_id": "hardcoded-system-program-address",
  "severity": "low",
  "confidence": 0.70,
  "description": "The program uses a hardcoded address for Token Program instead of using the proper constant. Using the constant ensures compatibility and follows Solana best practices.",
  "location": { "function": "validate_token", "offset": 0 }
}

Detection Methodology

The detector scans all CheckKey statements in the function:

  1. Constant extraction: For each CheckKey with a constant expected value, the detector extracts the byte representation.
  2. Known program matching: The extracted bytes are compared against a table of known system program addresses (System Program, Token Program, Token-2022 Program, Associated Token Program, Memo Program, BPF Loader Upgradeable, canonical NFT metadata).
  3. Finding generation: Matches generate a low-severity finding with the specific program name and recommended replacement constant.

Context modifiers:

  • Anchor programs: confidence reduced (Anchor uses typed program accounts)
  • Admin/initialization functions: confidence reduced by 40%

Limitations

False positives:

  • Constants that coincidentally match program address bytes but serve a different purpose will be flagged. Given the specificity of 32-byte addresses, this is unlikely.

False negatives:

  • Program addresses stored in non-constant expressions (e.g., loaded from config accounts) are not detected.
  • Custom or third-party program addresses (beyond the seven well-known programs tracked) are not flagged.

References