Deserialization Endianness
Detects potential endianness mismatches in data deserialization.
Deserialization Endianness
Overview
Remediation Guide: How to Fix Deserialization Endianness
The deserialization endianness detector identifies potential byte-order mismatches when deserializing multi-byte values from account data. Solana programs typically use little-endian byte order (via Borsh serialization), but programs that process data from external sources (oracles, bridges, network protocols) or perform manual byte manipulation may introduce endianness bugs.
Sigvex detects this by identifying multi-byte loads from account data followed by bit-shift operations at byte boundaries (shifts by 8, 16, or 24) without an explicit byte-swap operation, suggesting manual endianness handling that may not match the serialization format.
Why This Is an Issue
- Data corruption: interpreting a big-endian value as little-endian (or vice versa) produces a completely incorrect number, potentially orders of magnitude off.
- Financial impact: incorrect byte order on balance or price fields can lead to transfers of wrong amounts.
- Cross-chain interop: bridges and oracles may use big-endian (network byte order), conflicting with Solana’s native little-endian.
CWE mapping: CWE-198 (Use of Incorrect Byte Ordering).
How to Resolve
Native Solana
// Use explicit endianness conversion
let data = account.data.borrow();
// For Solana-native data (little-endian):
let value = u32::from_le_bytes(data[offset..offset + 4].try_into()?);
// For external data (big-endian/network byte order):
let value = u32::from_be_bytes(data[offset..offset + 4].try_into()?);
// Or use Borsh for consistent serialization:
let state = MyStruct::try_from_slice(&data)?;
Anchor
// Anchor uses Borsh (little-endian) consistently
#[account]
pub struct PriceData {
pub price: u64, // Always little-endian via Borsh
pub decimals: u8,
}
Examples
Vulnerable
let data = account.data.borrow();
let raw = u32::from_le_bytes(data[0..4].try_into()?);
// Manual byte extraction — may be wrong endianness
let byte0 = (raw >> 24) & 0xFF; // Big-endian extraction on little-endian data!
Fixed
let data = account.data.borrow();
// If data source is big-endian:
let value = u32::from_be_bytes(data[0..4].try_into()?);
// If data source is little-endian (Borsh):
let value = u32::from_le_bytes(data[0..4].try_into()?);
JSON Finding
{
"detector": "deserialization-endianness",
"severity": "Medium",
"confidence": 0.60,
"title": "Potential Endianness Mismatch in Deserialization",
"description": "Multi-byte value used in byte manipulation without explicit endianness conversion.",
"cwe": [198]
}
Detection Methodology
The detector tracks multi-byte loads from account data and byte-swap operations. When a loaded value is used in shift/mask operations at byte-aligned amounts (8, 16, 24) without a prior byte-swap or explicit from_le/from_be conversion, a finding is generated. Single-byte loads are excluded since they have no endianness concerns.
Limitations
- The detector relies on shift amounts to identify suspicious patterns and may miss endianness issues in arithmetic expressions.
- Programs that correctly use little-endian throughout may still be flagged if they perform byte extraction for non-endianness reasons.
- Borsh deserialization in Anchor programs eliminates most endianness concerns, reducing confidence significantly.
Related Detectors
- Unsafe Deserialization - detects bounds-checking issues in deserialization.
- Unchecked Deserialization - detects missing error handling.