Instruction Index Validation
Detects hardcoded instruction index comparisons that can be bypassed by attackers who control transaction structure.
Instruction Index Validation
Overview
Remediation Guide: How to Fix Instruction Index Validation
The instruction index validation detector identifies Solana programs that compare the current instruction index against hardcoded constants (e.g., index == 0 to ensure “this instruction is first in the transaction”). Attackers can bypass these checks by prepending harmless instructions to the transaction, shifting the target instruction to a different index.
This detector flags two patterns: direct comparisons of the current instruction index against constants, and loading instructions at hardcoded indices without first validating the total instruction count in the transaction.
Why This Is an Issue
Solana transactions can contain an arbitrary number of instructions, and the caller fully controls the transaction layout. A check like require!(current_index == 0) — intended to ensure the instruction runs first — is trivially bypassed by prepending a no-op instruction from any program. This makes the target instruction appear at index 1 instead of 0, bypassing the check entirely. Programs that rely on instruction ordering for security (e.g., flash loan repayment verification) are particularly vulnerable.
How to Resolve
use solana_program::sysvar::instructions::{
get_instruction_relative, load_current_index_checked,
load_instruction_at_checked,
};
pub fn verify_instruction_context(
ix_sysvar: &AccountInfo,
expected_program: &Pubkey,
) -> ProgramResult {
// Validate total instruction count instead of hardcoded index
let current = load_current_index_checked(ix_sysvar)? as usize;
// Verify the preceding instruction is from the expected program
if current > 0 {
let prev = load_instruction_at_checked(current - 1, ix_sysvar)?;
if prev.program_id != *expected_program {
return Err(ProgramError::InvalidArgument);
}
}
Ok(())
}
Examples
Vulnerable Code
pub fn enforce_first(ix_sysvar: &AccountInfo) -> ProgramResult {
let current = load_current_index_checked(ix_sysvar)?;
// Attacker prepends a no-op instruction, making this index 1
if current != 0 {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
Fixed Code
pub fn enforce_context(
ix_sysvar: &AccountInfo,
expected_count: u16,
) -> ProgramResult {
let current = load_current_index_checked(ix_sysvar)?;
// Validate total instruction count to prevent prepending attacks
let total = (current + 1) as u16; // Approximate; use get_instruction_count if available
if total != expected_count {
return Err(ProgramError::InvalidArgument);
}
Ok(())
}
Sample Sigvex Output
[HIGH] Hardcoded Instruction Index Comparison
Location: enforce_first (block 0, stmt 1)
Description: Instruction index is compared against hardcoded constant
(index == 0). Attackers can manipulate transaction structure by
prepending instructions.
CWE: CWE-807 (Reliance on Untrusted Inputs in a Security Decision)
Detection Methodology
- Index variable identification: The detector identifies variables assigned from syscalls that return the current instruction index (
load_current_index_checked,get_instruction_index). - Hardcoded comparison detection: It searches for conditional branches that compare identified index variables against constant values.
- Count validation awareness: If the program also queries the instruction count, confidence is reduced because the count check partially mitigates the risk.
- Hardcoded access detection: Direct calls to
load_instruction_atwith constant index arguments are flagged when no instruction count validation exists.
Limitations
False positives: Programs that validate instruction count alongside index checks may still be flagged, though with reduced confidence. Legitimate use of fixed transaction layouts (e.g., atomic swap protocols with exactly 2 instructions) may trigger findings. False negatives: Index values computed from expressions rather than direct constants may not be detected.
Related Detectors
- Instruction Introspection — detects missing bounds checks on introspection calls
- Implicit Instruction Ordering — detects ordering dependencies not enforced on all paths