Skip to main content
Sigvex

Account Executable Flag Remediation

How to fix missing executable flag validation before cross-program invocations.

Remediating Missing Executable Flag Validation

Overview

Related Detector: Account Executable Flag

When a Solana program performs a CPI using an account as a program ID without verifying that the account is executable or matches a known program address, an attacker can substitute a data account. The fix is to validate the program ID against a known constant or explicitly check the executable flag before invoking.

Before (Vulnerable)

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

pub fn proxy_call(accounts: &[AccountInfo]) -> ProgramResult {
    let target_program = &accounts[0]; // No validation!

    solana_program::program::invoke(
        &build_instruction(target_program.key),
        &[accounts[1].clone()],
    )?;
    Ok(())
}

After (Fixed)

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

const KNOWN_PROGRAM: Pubkey = /* expected program address */;

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

    // Validate program identity
    if target_program.key != &KNOWN_PROGRAM {
        return Err(ProgramError::IncorrectProgramId);
    }

    solana_program::program::invoke(
        &build_instruction(target_program.key),
        &[accounts[1].clone()],
    )?;
    Ok(())
}

Alternative Mitigations

  1. Use the account-validation framework’s Program<'info, T> type: This automatically validates both the program ID and executable flag. It is the strongest defense.
#[derive(Accounts)]
pub struct ProxyCall<'info> {
    pub target: Program<'info, TokenProgram>,
}
  1. Explicit executable check: If you cannot use a constant program ID (e.g., the program is configurable), check the executable flag directly.
if !program_account.executable {
    return Err(ProgramError::InvalidAccountData);
}
  1. Whitelist approach: Maintain a set of approved program IDs on-chain and validate against the whitelist.

Common Mistakes

  • Validating against a variable instead of a constant: Checking program.key == config.approved_program is only safe if config itself is properly validated (owner check + key check). Otherwise the attacker can pass a fake config account.
  • Checking executable flag without checking program identity: The executable flag confirms the account contains code, but a malicious program is also executable. Always validate the specific program ID.
  • Assuming the runtime check is sufficient: While the Solana runtime rejects CPI to non-executable accounts, relying solely on runtime validation produces confusing errors and misses the opportunity to validate program identity.
  • Forgetting nested CPI targets: If your program chains multiple CPIs, each program ID must be independently validated.

References