Remediating Input Validation
How to validate user-controlled instruction data and account fields in Solana programs.
Remediating Input Validation
Overview
Related Detector: Input Validation
All instruction data and account fields must be validated before use in security-critical operations. This includes bounds checking amounts, validating array indices, and verifying pubkey parameters.
Recommended Fix
Before (Vulnerable)
pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
let source = &accounts[0];
let dest = &accounts[1];
// No validation — amount could exceed balance
**source.lamports.borrow_mut() -= amount;
**dest.lamports.borrow_mut() += amount;
Ok(())
}
After (Fixed)
pub fn transfer(accounts: &[AccountInfo], amount: u64) -> ProgramResult {
let source = &accounts[0];
let dest = &accounts[1];
if amount == 0 {
return Err(ProgramError::InvalidArgument);
}
if amount > source.lamports() {
return Err(ProgramError::InsufficientFunds);
}
**source.lamports.borrow_mut() -= amount;
**dest.lamports.borrow_mut() += amount;
Ok(())
}
Alternative Mitigations
- Anchor constraints: Use
#[account(constraint = amount > 0)]for declarative validation. - Borsh with bounds: Implement custom
BorshDeserializethat validates ranges during deserialization.
Common Mistakes
- Validating only one bound: Checking
amount > 0but notamount <= balance. - Trusting account data without owner check: Validating instruction data but not verifying that account data comes from a trusted program.