Non-Anchor Discriminator Remediation
How to fix missing instruction discrimination in non-Anchor programs.
Non-Anchor Discriminator Remediation
Overview
Related Detector: Non-Anchor Discriminator
Missing instruction discrimination allows instruction confusion attacks. The fix is to implement explicit instruction routing using the first byte(s) of instruction data as a discriminator, with a default error case for unknown instructions.
Recommended Fix
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
let (discriminator, rest) = data.split_first()
.ok_or(ProgramError::InvalidInstructionData)?;
match discriminator {
0 => initialize(program_id, accounts, rest),
1 => deposit(program_id, accounts, rest),
2 => withdraw(program_id, accounts, rest),
_ => Err(ProgramError::InvalidInstructionData),
}
}
Alternative Mitigations
Borsh Enum Instruction Routing
Use Borsh-serialized instruction enums for type-safe routing:
#[derive(BorshDeserialize)]
pub enum Instruction {
Initialize { param: u64 },
Deposit { amount: u64 },
Withdraw { amount: u64 },
}
let instruction = Instruction::try_from_slice(data)?;
match instruction {
Instruction::Initialize { param } => initialize(accounts, param),
Instruction::Deposit { amount } => deposit(accounts, amount),
Instruction::Withdraw { amount } => withdraw(accounts, amount),
}
Common Mistakes
Mistake: Falling Through to Default Handler
// WRONG: unknown instructions processed by deposit handler
match tag {
0 => initialize(accounts),
_ => deposit(accounts, data), // Catch-all is dangerous
}
Always return an error for unknown discriminator values.