* docs: correct lifecycle and analysis workflow claims * docs: distinguish historical specifications from current guides * docs: align translated setup and MCP recovery guidance
3.5 KiB
Inspect a V8 code cache container
This specification records an implementation increment and its original problem statement. For current behavior and limitations, see the current guide.
Outcome
A bytenode .jsc, the bytes vm.Script.createCachedData() writes, and a code cache
carried inside a Node single-executable application or an Electron application are all
opaque today: the analysis reports the containing file and nothing about the cache. An
analyst has to install bytenode, guess a V8 version, and run the file to learn anything,
which executes attacker-controlled code and changes the state under study.
rea inspect-v8-code-cache <path> [--minStringBytes <n>] reads one explicitly selected
container as static bytes and reports its producer, the strings it retains above a
threshold, and the recoverable source metadata, without executing the file, starting a
V8 runtime, installing bytenode, or invoking a decompiler. The same facts are available
through the inspect_v8_code_cache MCP tool.
Requirements
- The reader accepts a file whose first words describe a V8 code cache header; anything else is refused before the payload is walked, so an unrelated file cannot be read as a cache by accident.
- The producer is decided from the header's producer bits, not from the file extension:
a module bit means
vm.SourceTextModule, a compile-function bit meansvm.compileFunction, and neither bit meansunknown. The unflagged case is notvm.Scriptby inference — whether V8 marks a function cache is a build detail. Avm.compileFunctioncache reads0x20000004for a 4-unit source on Node 24.22.1 and0x00000004on Node 22.23.4, so an unflagged word could be either producer. The observed word stays inheader.fieldsfor a caller that trusts a specific build fingerprint. - Retained strings are reported above the caller's byte threshold, with
--minStringBytesbounded so a pathological threshold cannot make the read unbounded. - Observation is bounded by a budget that reports which bound it hit and how to raise it, rather than silently truncating.
- The container's file location is reported as given, and the payload is never written back or repaired.
Non-goals
- Decoding the payload back into source. The container's bytecode is version-specific and the tool does not attempt to reconstruct source from it.
- Executing the container to obtain runtime facts.
- Recognising an encrypted or compressed wrapper around a cache.
Verification
- The
vm.Scriptproducer word and its retained strings come from output this suite generates throughvm.Script.createCachedData(), and thevm.compileFunctioncase compiles throughvm.compileFunctionfor the same reason. - The
vm.SourceTextModuleproducer bit is checked by setting the measured bit on a realvm.Scriptcache rather than by compiling throughvm.SourceTextModule, so that case covers the bit's meaning and not a cache from that producer. - The CLI, MCP, absolute-path and decimal-argument boundary contracts have their own tests.
- The budget tests call
observationBudgetRecoveryand assert its structured facts — the boundary reached and which knob may move.observationBudgetRemediationrenders that struct into a sentence, so it is held to the struct rather than to its wording: the sentence must not advise a knob the struct closed, and must mention a smaller artifact exactly when the struct requires one. Rewording stays free; wrong advice does not.