Skip to main content
Sigvex

Instruction Introspection Remediation

How to fix unsafe instruction introspection with missing bounds or length validation.

Instruction Introspection Remediation

Overview

Related Detector: Instruction Introspection

Instruction introspection via the Instructions sysvar allows programs to inspect other instructions in the same transaction. Accessing an instruction by index without verifying the transaction contains enough instructions causes a runtime panic. The fix requires validating the instruction count before index-based access and validating data length before deserialization.

Before (Vulnerable)

pub fn verify_flash_loan(ix_sysvar: &AccountInfo) -> ProgramResult {
    let repay_ix = load_instruction_at_checked(2, ix_sysvar)?;
    let amount = u64::from_le_bytes(repay_ix.data[0..8].try_into().unwrap());
    Ok(())
}

After (Fixed)

pub fn verify_flash_loan(ix_sysvar: &AccountInfo) -> ProgramResult {
    // 1. Validate instruction count
    let current = load_current_index_checked(ix_sysvar)? as usize;
    if current + 1 < 3 {
        return Err(ProgramError::InvalidArgument);
    }

    // 2. Load instruction with validated index
    let repay_ix = load_instruction_at_checked(2, ix_sysvar)?;

    // 3. Validate data length before deserialization
    if repay_ix.data.len() < 8 {
        return Err(ProgramError::InvalidInstructionData);
    }
    let amount = u64::from_le_bytes(repay_ix.data[0..8].try_into().unwrap());
    Ok(())
}

Alternative Mitigations

Use CPI instead of introspection when possible. Cross-program invocations are safer because the callee validates its own inputs, and you do not need to reason about transaction-level instruction ordering.

Validate the total instruction count at the program entry point rather than at each introspection site. This centralizes the check and ensures all downstream introspection calls are safe.

Common Mistakes

Assuming a fixed transaction layout. Attackers control which instructions appear in a transaction and in what order. Never assume instruction index N always contains a specific program’s instruction.

Checking only the index but not the data length. Even if the instruction exists, its data payload may be shorter than expected.

Using relative offsets without accounting for prepended instructions. If you access current_index - 1, verify that current_index > 0 first.

References