Skip to main content
Sigvex

Unsafe Deserialization Remediation

How to fix unsafe account data access patterns.

Unsafe Deserialization Remediation

Overview

Detector Reference: Unsafe Deserialization

This guide explains how to fix unsafe account data access patterns that lack bounds checking.

Always validate that offsets and sizes are within bounds before accessing account data:

let data = account.data.borrow();
let offset = compute_offset(instruction_data)?;
let size = std::mem::size_of::<u64>();

// Bounds check
if offset.checked_add(size).map_or(true, |end| end > data.len()) {
    return Err(ProgramError::InvalidAccountData);
}

let value = u64::from_le_bytes(data[offset..offset + size].try_into()?);

Alternative Mitigations

  1. Use Borsh deserialization: MyStruct::try_from_slice(&data) handles bounds checking internally.
  2. Fixed offsets: use compile-time constants for field offsets and validate account data length once at instruction entry.
  3. Anchor typed accounts: Account<'info, MyState> deserializes with built-in bounds validation.

Common Mistakes

  • Integer overflow in offset calculation: offset + size can overflow. Use checked_add() for safety.
  • Trusting instruction data for offsets: user-supplied offsets must always be validated against account length.
  • Checking length once for multiple reads: if you perform multiple reads at different offsets, validate each one or validate the maximum required length upfront.

References