Skip to main content
Sigvex

Instruction Verification Pattern Remediation

How to fix incorrect ordering of validation checks and sensitive operations.

Instruction Verification Pattern Remediation

Overview

Related Detector: Instruction Verification Pattern

Instruction verification pattern violations occur when a program performs sensitive operations (state writes, transfers, CPIs) before completing all required validation checks. The fix is to structure every instruction handler with a clear validation-then-execute pattern: perform all signer, owner, and key checks before any state modification or fund transfer.

Before (Vulnerable)

pub fn process(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
    let user = &accounts[0];
    let vault = &accounts[1];

    // Writes state before checking authorization
    let mut vault_data = vault.try_borrow_mut_data()?;
    vault_data[0..8].copy_from_slice(&data[0..8]);

    if !user.is_signer {
        return Err(ProgramError::MissingRequiredSignature);
    }
    Ok(())
}

After (Fixed)

pub fn process(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
    let user = &accounts[0];
    let vault = &accounts[1];

    // All validation first
    if !user.is_signer {
        return Err(ProgramError::MissingRequiredSignature);
    }
    if vault.owner != &crate::ID {
        return Err(ProgramError::IncorrectProgramId);
    }

    // State modification only after validation
    let mut vault_data = vault.try_borrow_mut_data()?;
    vault_data[0..8].copy_from_slice(&data[0..8]);
    Ok(())
}

Alternative Mitigations

Use an account-validation framework constraints to enforce validation before the handler body executes:

#[derive(Accounts)]
pub struct UpdateVault<'info> {
    #[account(mut, has_one = authority)]
    pub vault: Account<'info, Vault>,
    pub authority: Signer<'info>,
    // Anchor verifies signer + ownership before handler runs
}

Extract a validation function that returns a validated context struct. The handler only receives the struct, ensuring validation always precedes execution.

Common Mistakes

Performing validation in only one branch of a conditional. If a function branches on user input, both paths must validate before executing sensitive operations.

Checking the signer but not the owner. Both checks are typically required. A valid signer operating on an account owned by the wrong program can still cause damage.

Assuming CPI callees will validate. The calling program must validate its own preconditions before invoking another program. The callee validates its own constraints, not the caller’s.

References