# Evidence integrity

URL: /concepts/evidence-integrity

Foxborne keeps each original exactly as it arrived and ties every event, excerpt and report line back to it. Anyone holding the file can check a finding against it.



A review board signs off on evidence, not on a tool's say-so. Foxborne keeps an unbroken chain from each file to each line of a report. Someone who holds the original can check every link in it.

## Hashed the moment it arrives [#hashed-the-moment-it-arrives]

Foxborne computes the SHA-256 of each original before it parses anything. A file dropped into **Import files** is hashed in your browser, and its row reads **computed in your browser** beside the digest. Files from connected storage are hashed on arrival too: "Every file is hashed with SHA-256 before parsing and stored unmodified."

A run's **Source files** panel repeats the promise under its title: "Hashed on arrival and stored unmodified." The **SHA-256** column shows the first 12 and last 4 hex digits, and its copy button copies all 64.

The collector applies your redaction patterns on the vehicle, before upload. Nothing is changed after the hash.

## Originals are write-once [#originals-are-write-once]

Originals live in object storage you own, encrypted with your key. The **Hosting** page puts it plainly: "Written once. Foxborne cannot modify or delete an original."

Normalized events and notes are kept apart from the files, in PostgreSQL inside your network. Foxborne's access to connected storage is read-only. When an admin adds a storage source, its connection test tries a write and a delete and reports both refused.

A file that fails a check is never altered to fit:

| Problem                                    | What Foxborne does                                               |
| ------------------------------------------ | ---------------------------------------------------------------- |
| Larger than the per-file limit             | Refuses it with a reason. Oversized files are never truncated.   |
| Named `.ulg` without the ULog magic bytes  | Quarantines it: the file may be corrupt or not a PX4 log.        |
| Flight log truncated inside a data message | Quarantines the run. Nothing from the file is shown as complete. |
| Encrypted flight log                       | Rejects it. Foxborne does not decrypt logs.                      |

Your retention policy decides when originals are deleted, and each deletion comes with a certificate that lists each hash. Runs on legal hold are never deleted, whatever the policy. See [Retention, holds and redaction](/security/retention).

## Same file, same event IDs [#same-file-same-event-ids]

Parsing turns each original into events, and each event gets a stable ID of 8 hex characters. A run's **Import job** drawer states the rule: "Deterministic. The same files and parser versions give the same event IDs."

Each file records the parser version that read it, in the **Parser** column of the run page and in each excerpt the report quotes. The example dataset shows `ulog 0.9.2`, `journal 0.6.0`, `agent 0.8.1` and `receive 0.4.1`. An event ID in a report therefore points at the same record for anyone who parses the same file with the same parser version.

## Excerpts name their place in the file [#excerpts-name-their-place-in-the-file]

Foxborne quotes evidence exactly and says where it came from: the file, the location in it and the file's SHA-256. The location depends on the format:

| Source             | Location                       | Example from INC-0142              |
| ------------------ | ------------------------------ | ---------------------------------- |
| Flight log         | Message number and byte offset | Message 1,146,099, byte 53,503,302 |
| Companion journal  | Line                           | Line 18,314                        |
| Process samples    | Rows                           | Rows 2,811 to 2,813                |
| Ground receive log | Lines                          | Lines 1,118 and 1,119              |

The report's **3 Evidence** section prints each excerpt with its file, location, short hash, parser and event ID. **Copy reference**, in the evidence inspector, copies one line that holds the same facts:

```text caption="Format of a copied evidence reference"
<incident ID>/<event ID> <file name> sha256:<full hash> <location>
```

A case file keeps the same discipline. Its **3 Evidence** section quotes each excerpt with its file, location and SHA-256, and every export carries a SHA-256 manifest of its files. The report's footer adds: "Every excerpt can be checked against its SHA-256."

[Verify a report against the originals](/investigate/verify) walks through the check.

## Notes and dismissals sit beside the evidence [#notes-and-dismissals-sit-beside-the-evidence]

Nothing an engineer writes changes an original. The import page says of notes: "Saved as an annotation with your name. Notes are never treated as evidence."

Comments on an event page go in its **Discussion** drawer, opened beside the record, and each one is audited.

Dismissing a finding takes a written reason. The dialog states "The raw evidence is not changed," and the confirmation repeats it: "Finding dismissed. The evidence is unchanged."

The inspector then shows who dismissed the finding and why, and the audit log keeps the dismissal and its reason.

## Results you can reproduce [#results-you-can-reproduce]

Rules are deterministic and versioned. Each finding records the rule ID, version and threshold that produced it and the events it read.

**Run rules again**, on a run's page, runs the rules once more and reports "Rules ran again. Results are identical to the previous run."

A threshold change saves the rule as a new version, and findings already produced keep the version that made them. See [Rules and findings](/concepts/rules-and-findings).

## One audit chain for every action [#one-audit-chain-for-every-action]

The audit log records "every import, view, edit, export and administrative change." Opening a piece of evidence counts: each view writes a **Viewed evidence** entry.

Each entry carries the hash of the one before it, so a missing or altered entry breaks the chain. **Verify chain** recomputes each hash from the entry and the hash before it. Entries also stream to your SIEM over syslog with TLS, and an export of the log carries both hashes so it can be verified offline.

## Related [#related]

* [Verify a report against the originals](/investigate/verify) checks a report line by line.
* [Audit log](/security/audit-log) covers the hash chain, its verification and its export.
* [Import files in the console](/collect/import-files) covers hashing, validation and limits on upload.
* [Reports and case files](/concepts/reports) shows where excerpts and hashes sit in a report.
