Skip to main content
Sigvex

Zero Copy Deserialization Remediation

How to fix unsafe zero-copy deserialization patterns.

Zero Copy Deserialization Remediation

Overview

Detector Reference: Zero Copy Deserialization

This guide explains how to fix unsafe zero-copy deserialization patterns that can lead to buffer over-reads, type confusion, and alignment violations.

Always validate size, discriminator, and use safe transmutation:

let data = account.data.borrow();

// 1. Size check
require!(data.len() >= 8 + std::mem::size_of::<MyStruct>(), InvalidAccountData);

// 2. Discriminator check
require!(data[0..8] == EXPECTED_DISCRIMINATOR, InvalidAccountData);

// 3. Safe transmutation
let state: &MyStruct = bytemuck::try_from_bytes(&data[8..8 + std::mem::size_of::<MyStruct>()])
    .map_err(|_| ProgramError::InvalidAccountData)?;

Alternative Mitigations

  1. Anchor AccountLoader: use #[account(zero_copy)] and AccountLoader<'info, T> for safe zero-copy access with automatic validation.
  2. zerocopy crate: use FromBytes::read_from() which validates size and alignment.
  3. bytemuck::try_pod_read_unaligned(): for potentially unaligned data, this handles alignment safely.

Common Mistakes

  • Using bytemuck::from_bytes instead of try_from_bytes: the non-try version panics on invalid input.
  • Skipping discriminator checks: zero-copy is especially dangerous without type validation since any bytes can be reinterpreted as the target struct.
  • Ignoring padding: zero-copy structs may have padding bytes that contain data from previous account occupants. Use #[repr(C)] and Pod derive to ensure predictable layout.
  • Assuming alignment: Solana account data is not guaranteed to be aligned. Use try_pod_read_unaligned or copy to an aligned buffer.

References