Skip to main content

Module v8_value

Module v8_value 

Source
Expand description

V8 / Blink structured-clone value deserializer.

When Chromium persists a JavaScript value — an IndexedDB record, a postMessage payload, a Service Worker cache entry — it serializes it with V8’s ValueSerializer (the structured clone wire format), optionally wrapped in Blink’s SerializedScriptValue envelope. This module decodes those bytes back into a structured V8Value, so an opaque IndexedDB blob unwraps the way blob-decoder already unwraps bplist / gzip / protobuf.

§Wire format

A V8 stream opens with a version header (0xFF + an LEB128 version) and is then a sequence of one-byte serialization tags, each introducing a typed value; lengths are unsigned LEB128 varints and kInt32 is zig-zag encoded. Blink prepends its own 0xFF <blink-version> and an optional 0xFE trailer (an 8-byte BE offset + 4-byte BE size) before the nested V8 payload.

Authoritative references (decode logic below is a clean-room Rust reimplementation, not a port of the C++):

  • V8 src/objects/value-serializer.cc — the SerializationTag enum, varint framing, the 0xFF version header.
  • Blink .../serialization/serialization_tag.h — the 0xFF/0xFE envelope.

The canonical tag→name tables live in the fleet knowledge crate forensicnomicon-core::v8_serialization (module present in the source tree, not yet on crates.io as of forensicnomicon-core 1.4.0). The individual tag byte constants a decoder must match on are mirrored here from that source; migrate to the published constants once that module ships to the registry.

§Safety

All input is attacker-controllable. The invariant is: never panic, never read out of bounds, never trust a length field, never OOM. Every read is bounds-checked (returns V8Error, never indexes blindly), recursion is depth-capped, and total materialized nodes are budget-capped so a crafted blob (deep nesting, huge sparse-array length, reference amplification) fails loud instead of exhausting memory or the stack.

Structs§

V8Limits
Resource bounds for the deserializer — the guard against stack overflow, unbounded allocation, and reference-amplification on untrusted input.

Enums§

V8Error
A decode failure. Every arm names what failed and where (byte offset), and surfaces the offending value (tag byte / id) so an analyst can identify it — an “unknown” is never reported without the bytes that were actually there.
V8Value
A decoded V8 / Blink structured-clone value.

Functions§

deserialize
Deserialize a raw V8 ValueSerializer stream (0xFF <version> <value>) with default V8Limits.
deserialize_blink
Deserialize a Blink SerializedScriptValue (the on-disk IndexedDB form): the Blink 0xFF <version> envelope, an optional 0xFE trailer, then the nested V8 payload. Falls back to a raw V8 read when no Blink envelope is present.
deserialize_blink_with_limits
Deserialize a Blink SerializedScriptValue with explicit V8Limits.
deserialize_with_limits
Deserialize a raw V8 stream with explicit V8Limits.
is_value_tag
True when tag opens a value we recognise — used by the identifier to decide whether a 0xFF-led blob is plausibly V8 before reporting a failed decode.