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— theSerializationTagenum, varint framing, the0xFFversion header. - Blink
.../serialization/serialization_tag.h— the0xFF/0xFEenvelope.
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
ValueSerializerstream (0xFF <version> <value>) with defaultV8Limits. - deserialize_
blink - Deserialize a Blink
SerializedScriptValue(the on-disk IndexedDB form): the Blink0xFF <version>envelope, an optional0xFEtrailer, 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
SerializedScriptValuewith explicitV8Limits. - deserialize_
with_ limits - Deserialize a raw V8 stream with explicit
V8Limits. - is_
value_ tag - True when
tagopens a value we recognise — used by the identifier to decide whether a0xFF-led blob is plausibly V8 before reporting a failed decode.