JOEY VICTORINO Independent Technical Judgment

Field Notes · Technical Notes · 7 min read

Forensic parsers should fail closed.

Evidence-processing software regularly encounters input it cannot fully read: truncated acquisitions, databases captured mid-write, records that fail their own integrity checks, structures from a version the parser predates. A tool that skips those quietly and continues produces output that looks complete. The analyst then counts records, builds a timeline, and states a conclusion whose real support is unknown, because the gap the parser created is invisible. Failure behavior is part of evidentiary integrity, and it should be specified rather than inherited from whatever the error handling happened to do.

The failure that matters is silent, not loud

A parser that crashes on bad input is an inconvenience: the analyst knows something went wrong and deals with it. A parser that returns a clean result set while having dropped an unknown fraction of the source is a different category of problem, because it produces a confident artifact with no marker of its own incompleteness.

The consequence propagates in a specific way. The parser emits records. The analyst treats the record set as the population, not the sample. The timeline is built on the population. The report states "no evidence of X was observed." The reader of the report, typically an executive or counsel, treats that as a determination about the system. In fact it is a determination about whatever survived a silent filter that nobody described. That companion problem, conclusions inheriting the limits of the evidence beneath them, is the subject of Evidence Gaps Are Findings. The distinguishing feature here is that this gap is not merely unstated: it is undiscoverable from the output, which places it beyond the reach of an analyst's diligence.

Where real evidence stops being well-formed

This is not a hypothetical class of input. Ordinary acquisition and ordinary operating-system behavior produce artifacts that are legitimately hard to read, and each carries a different interpretive risk:

  • Truncation. Acquisition interrupted, a volatile source that ended mid-record, a container copied while still being written. The final record is partial. A parser can reasonably discard it; what it cannot reasonably do is discard it without saying so, because a truncated tail is exactly where the most recent activity lives.
  • Dirty state in transactional stores. Many artifacts of interest are transactional databases captured without a clean shutdown. SQLite in write-ahead logging mode keeps recent committed transactions in a separate -wal file until a checkpoint folds them into the main database. Parsing the main file alone yields a view that is internally consistent and stale: the most recent writes are simply absent, and nothing in the main file announces their existence. Registry hives have an analogous property, with pending changes held in transaction logs that must be replayed to reconstruct the state at acquisition.
  • Integrity check failures. Formats that carry checksums or per-chunk validation, including structured event logs, can present regions that do not verify. Sometimes the surrounding data is still recoverable and worth recovering. Recovery under a failed integrity check is a legitimate operation and a materially different claim from recovery under a passing one, and the two should never appear identically in output.
  • Unsupported or newer structures. The source system was more current than the tool. Unknown record types, added fields, changed layouts. A parser that treats an unrecognized structure as absent has silently answered a question it could not read.
  • Encoding and value coercion. Invalid byte sequences replaced with substitution characters change strings. A malformed or absent timestamp rendered as an epoch default manufactures a fact: a record that appears to have occurred in 1970 or 1601 is not a record with an odd date, it is a record whose time is unknown, and those two statements support different conclusions.

What fail-closed actually means here

Fail-closed does not mean refusing to process imperfect evidence. Imperfect evidence is most evidence, and a tool that halts on the first anomaly is useless in real work. It means the tool must never represent a degraded result as a complete one. Concretely:

  1. Separate "nothing found" from "could not read." These are different results and they cannot share a representation. An empty result set with no error is a positive claim about the source; it should be emitted only when the parser actually read the source and found nothing.
  2. Make status per-record, not only per-file. Every emitted record should carry its own provenance and confidence: which source, which offset or region, whether its integrity check passed, whether any field was reconstructed or defaulted. Per-file summaries hide exactly the variation that matters.
  3. Report completeness quantitatively. Bytes processed against bytes present. Records recovered against records the container declares it holds, where the format states a count. Regions skipped, with reasons. An analyst who can see that 8% of a container was unreadable knows something important about every negative conclusion drawn from it.
  4. Never fabricate values. Missing is a value. Unparseable is a value. Neither is zero, epoch, empty string, or the previous record's field. Coercion to a plausible default is the single most damaging habit in this class of software, because it produces data that is indistinguishable from evidence downstream.
  5. Verify integrity before and after. Hash the source at acquisition, verify before parsing, and record both in the output. Integrating verification into the workflow is long-standing practice in forensic guidance, and its value is not the ritual: it is that a later dispute about whether the analyzed object matched the acquired object becomes a documented question rather than an argument.
  6. Propagate uncertainty across pipeline stages. Parsers usually feed normalizers, correlators, and timeline builders. If per-record status does not survive those stages, the pipeline reconstitutes the original problem at a higher layer: a timeline that renders reconstructed and verified records identically has erased the distinction the parser was careful to preserve.
  7. Make status machine-readable. A warning printed to standard error is invisible to an automated pipeline and to a hurried human. Degraded parses should be expressed in structured output and in exit status, so that automation can route them for review rather than aggregating them into a dashboard.

The design tension, stated honestly

The strongest objection to this position comes from practitioners who do recovery work: strict parsers recover less. Real-world artifacts are frequently damaged, and a tool willing to make aggressive inferences about partial structures can surface records that a conservative parser would drop. In an investigation with limited evidence, those records are sometimes the case.

The objection is correct, and it argues for a different resolution than strictness. The problem is not aggressive recovery; it is undeclared aggressive recovery. A tool can carve, infer, and reconstruct as far as its authors dare, provided every product of that process is labeled as what it is, and provided the labels survive into the analyst's working set and the final report. Recovery mode and verified-parse mode should be distinguishable in the output, not only in the invocation. What is unacceptable is a single undifferentiated stream in which a record read cleanly from an intact structure and a record reconstructed from a damaged one look identical.

A second, narrower boundary: some formats genuinely do not declare their own expected record counts, so completeness cannot always be expressed as a ratio. Where the format cannot support the measurement, the tool should say that too. "Completeness not determinable for this format" is an honest and useful output. An unqualified record count is not.

Why an executive should care about parser semantics

This appears to be an engineering concern, and it becomes a governance concern at the moment a conclusion is relied upon. Decisions with real consequences, whether to notify customers, whether to declare an incident closed, whether to advance a contested technical position, rest on statements produced by tooling. If the tooling cannot describe its own coverage, then neither can the report built on it, and the organization is making a decision on evidence of unknown completeness while believing otherwise.

There is also an adversarial dimension. A conclusion that must withstand challenge from opposing counsel, a regulator, an insurer, or an acquirer's technical advisers will be probed at exactly this seam: what did the tool examine, what did it fail to examine, and how do you know. Tool validation is an established discipline for this reason; NIST's Computer Forensics Tool Testing program exists to evaluate tools against documented specifications precisely because the reliability of the instrument bounds the reliability of the finding. An analyst who can answer the coverage question from the artifact itself is in a materially stronger position than one relying on the tool's reputation.

What to require

For a technical leader who is not going to read parser source, four requirements are enough to change the outcome. First, require that every evidence-derived report state its coverage: what was examined, what was unreadable, what was reconstructed. Second, require that "no evidence of X" statements identify the sources and periods they cover, a discipline this corpus applies to closure decisions as well. Third, require that tooling used for consequential work be able to distinguish verified from reconstructed output, and ask to see an example of that distinction rather than accepting the assurance. Fourth, when a pipeline is built in-house, make failure behavior an explicit design requirement reviewed like any other, rather than an emergent property of the error handling.

Conclusion

Evidence-processing software makes a claim every time it emits a result, and the claim is stronger than most tools are built to support: this is what the source contained. Where the source was truncated, dirty, unverifiable, or newer than the parser, the honest claim is narrower and shaped differently. Building tools that make the narrower claim accurately costs little at design time and is nearly impossible to retrofit into a conclusion after the fact, because by then the missing records are indistinguishable from records that never existed. Fail-closed is not conservatism. It is the requirement that a tool's output be a truthful statement about what the tool actually did.

When the technical conclusion is contested

Independent technical judgment is most useful where a conclusion carries consequence and the evidence behind it deserves examination: incidents whose closure is in question, disputes where technical facts decide the commercial outcome, and investigations where what was not examined matters as much as what was. That work is described under Special Situations.

Know an incident response or detection engineering team building evidence tooling? This note is for them.

Sources

  • National Institute of Standards and Technology, Computer Forensics Tool Testing Program (CFTT). Cited for the existence and purpose of systematic forensic tool validation against documented specifications.
  • SQLite, Write-Ahead Logging. Cited for the behavior of WAL mode: committed transactions are written to a separate log file and are folded into the main database only at checkpoint, so the main database file alone may not reflect the most recent committed writes.
  • National Institute of Standards and Technology, SP 800-86, Guide to Integrating Forensic Techniques into Incident Response. Cited for the role of data integrity verification, including hashing acquired data, within a defensible forensic process.

← All Field Notes