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.
Recommended Fix
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
- Anchor
AccountLoader: use#[account(zero_copy)]andAccountLoader<'info, T>for safe zero-copy access with automatic validation. zerocopycrate: useFromBytes::read_from()which validates size and alignment.bytemuck::try_pod_read_unaligned(): for potentially unaligned data, this handles alignment safely.
Common Mistakes
- Using
bytemuck::from_bytesinstead oftry_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)]andPodderive to ensure predictable layout. - Assuming alignment: Solana account data is not guaranteed to be aligned. Use
try_pod_read_unalignedor copy to an aligned buffer.