Parse Chrome, Firefox, and Safari — and embedded-Chromium apps — into one JSON timeline. Detect history clearing. Carve deleted records. No runtime deps.
Browser artifacts are present in almost every investigation — they reconstruct the user's timeline, expose credential exposure, and often reveal the delivery mechanism for an attack. The problem is tooling: most parsers require Python, lock you to Windows, or ignore the forensically interesting question of whether the evidence was tampered with.
br4n6 is a single static Rust binary. Point it at a browser database and get JSON. Point it at a profile directory and get a full triage report with integrity indicators and carved deleted records. Point it at an evidence tree and it sweeps out every browser and every embedded-Chromium app (Electron, WebView2, CEF) it can structurally identify.
cargo install --git https://github.com/SecurityRonin/browser-forensic browser-forensic-cli
br4n6 history /path/to/Chrome/Default/History --format jsonl | jq 'select(.attrs.url | test("google.com"))'From source
git clone https://github.com/SecurityRonin/browser-forensic.git
cd browser-forensic
cargo build --release
./target/release/br4n6 --help# Chrome history — last 30 days, sorted by time
br4n6 history /path/to/Chrome/Default/History --format jsonl \
| jq -r '[.timestamp_ns, .attrs.url, .attrs.title] | @tsv' \
| sort | tail -100
# Firefox — same command, different path
br4n6 history /path/to/Firefox/Profiles/abc.default/places.sqlite --format jsonlEvery supported browser produces the same BrowserEvent JSON schema. Your downstream analysis pipeline doesn't need to know which browser produced the data.
br4n6 integrity /path/to/Chrome/Default/History --format jsonl{"HistoryCleared":{"browser":"Chromium","path":"/path/to/History","detected_at_ns":1700000000000000000}}
{"AutoIncrementGap":{"path":"/path/to/History","table":"urls","max_rowid":2,"auto_increment":847}}
{"VisitIdGap":{"path":"/path/to/History","expected_id":3,"found_id":851}}Three indicators in under 100ms. The sqlite_sequence table recorded 847 URL insertions; only 2 rows remain. IDs jump from 2 to 851. The user cleared their history — and this database says exactly when the last visible record was written.
br4n6 carve /path/to/Chrome/Default/History --format jsonlSQLite marks deleted rows as free pages rather than overwriting them immediately. br4n6 carve walks the freelist chain, scans each free page for URL patterns, and returns whatever survived (via the published sqlite-forensic recovery engine). Combine with br4n6 integrity to establish what was deleted and what was recovered.
browser-forensic now matches the artifact breadth of the mainstream browser-history tools — including web storage (Local / Session Storage, IndexedDB) and embedded-Chromium container discovery — and adds forensic depth those tools do not carry: integrity/tampering detection, free-page carving, WAL recovery, memory scanning, and an embeddable Rust library.
| Capability | browser-forensic | Hindsight | Browser-Reviewer |
|---|---|---|---|
| Chrome / Chromium | ✅ | ✅ | ✅ |
| Firefox | ✅ | ✅ | ✅ |
| Safari | ✅ | — | — |
| Web storage (Local / Session / IndexedDB) | ✅ | ✅ | ✅ |
| URL / cookie interpretation | ✅ | ✅ | — |
| Embedded-Chromium container discovery | ✅ | — | ✅ |
| Integrity / tampering detection | ✅ | — | — |
| SQLite free-page carving | ✅ | — | — |
| WAL recovery | ✅ | — | — |
| Memory byte-pattern scanning | ✅ | — | — |
| Correlated XLSX / SQLite export | ✅ | ✅ | — |
| Embeddable library | ✅ | — | — |
| Runs on Linux / macOS / Windows | ✅ | ✅ | Windows only |
Reflects each tool's documented feature set as of mid-2026. Hindsight parses Chromium (and, more recently, Firefox) profiles in Python; Browser-Reviewer is a portable Windows GUI/CLI for Firefox and Chromium.
| Artifact | Chrome / Chromium¹ | Firefox | Safari |
|---|---|---|---|
| History | ✅ | ✅ | ✅ |
| Cookies | ✅ | ✅ | ✅ |
| Downloads | ✅ | ✅ | ✅ |
| Bookmarks | ✅ | ✅ | ✅ |
| Extensions / Add-ons | ✅ | ✅ | ✅ |
| Autofill | ✅ | ✅ | — |
| Login Data (no passwords) | ✅ | ✅ | — |
| Cache | ✅ | ✅ | — |
| Session State | ✅ | ✅ | — |
| Preferences | ✅ | ✅ | — |
| Top Sites | — | — | ✅ |
| Profile Metadata (Local State) | ✅ | — | — |
| Web Storage (Local / Session / IndexedDB) | ✅ | ✅ | — |
| Integrity indicators | ✅ | ✅ | ✅ |
| SQLite free-page carving | ✅ | ✅ | ✅ |
| WAL recovery | ✅ | ✅ | ✅ |
¹ Chromium-family covers Chrome, Edge, Brave, Opera, Vivaldi, and Arc — one engine, one set of parsers.
br4n6 storage reads the three web-storage backends the browsers use, emitting the same BrowserEvent schema as every other artifact:
br4n6 storage /path/to/Chrome/Default --format jsonl- Chromium Local / Session Storage — LevelDB, decoded through the published
leveldb-forensiccrate. - Chromium IndexedDB — LevelDB-backed; values are Blink/v8-serialized and surfaced as opaque raw records rather than a fabricated decode.
- Firefox web storage — plain SQLite (
webappsstore.sqliteandstorage/default/*/idb/*.sqlite).
Each event carries a storage_type attr (local_storage, session_storage, indexeddb) so downstream filtering stays simple.
Modern desktop apps embed Chromium — Slack, Teams, OneDrive, and hundreds of Electron / WebView2 / CEF apps keep the same history, cookies, and web-storage databases a browser does. br4n6 browsers --sweep recursively walks an evidence tree, identifies each container by its structural profile markers (backed by forensicnomicon::browser_profiles), and attributes it to the owning app:
br4n6 browsers --sweep /mnt/evidence/Users/jsmith --format jsonlThe sweep reports every browser profile and embedded-Chromium container found, with the app name, vendor, and how it embeds Chromium (Browser / Electron / WebView2 / Cef). A profile-shaped directory that matches no catalog entry is still reported, generically labelled — nothing is silently dropped.
br4n6 integrity detects raw structural anomalies — observable facts about the database, not forensic conclusions:
HistoryCleared / AutoIncrementGap — sqlite_sequence recorded N insertions; fewer than N rows remain. The auto-increment counter is the shadow of everything that was ever inserted, including what was deleted.
VisitIdGap — visit IDs must be monotonically assigned. A gap of 840 IDs between row 2 and row 851 means 840 visit records were inserted and then deleted.
TimestampNonMonotonic — visit timestamps must not go backward within a session. A timestamp earlier than the preceding visit indicates record injection or manual table manipulation.
CookieTimestampAnomaly — a cookie whose creation_utc is later than its last_access_utc cannot exist naturally. The access timestamp predates the cookie's creation — the record was fabricated or the timestamps were edited.
WalPresent — a -wal file alongside the database means unflushed writes exist that are not reflected in the main file. The WAL contains the most recent state; ignoring it produces an incomplete picture.
SqliteIntegrityFailure — PRAGMA integrity_check reports structural corruption. This ranges from benign (interrupted write) to deliberate (anti-forensic page manipulation).
HistoryTombstoneFound (Safari) — Safari maintains a history_tombstones table for deleted history items. Tombstones are direct evidence that history was deleted, with the deletion timestamp preserved in the schema.
DownloadFileMissing — a download record exists with a local target path, but the file is absent. The download completed; the file was removed.
# Discover all browser profiles under the user's home directory,
# parse every artifact, run integrity checks, and carve free pages
br4n6 triage --home /mnt/evidence/Users/jsmith --format jsonl > report.jsonlThe triage report includes:
- All parsed browser events across Chromium, Firefox, and Safari
- Integrity indicators from every database found
- Carved records from SQLite free pages and WAL files
- A manifest of discovered profiles (browser, name, path, container attribution)
- Generation timestamp for chain-of-custody documentation
--interpret adds a human-readable interpretation to each event, decoding the
artifacts that carry hidden structure. The interpretation engine is a clean-room
reimplementation of the Hindsight interpretation plugins:
- Google searches — extracts the query and search options from
google.*/searchURLs (Searched for "how to wipe a disk"). - Query strings — decodes any URL's parameters into
key: valuepairs. - Google Analytics cookies —
__utma/__utmb/__utmc/__utmv/__utmz/_ga(visitor IDs, first/last visit times, campaign sources). - Tracking / infrastructure cookies — F5 BIG-IP
BIGipServer*(decodes the backendIP:port), Quantcast__qca, and a generic embedded-timestamp scan.
Timestamps are inferred by magnitude (Unix seconds/millis/micros or WebKit), matching the ground truth without the caller declaring units. Cookie interpretation runs where a plaintext value is available (Firefox); Chrome cookie values stay encrypted and are never surfaced.
br4n6 export /mnt/evidence/Users/jsmith --interpret --format jsonl \
| jq 'select(.interpretation | test("Searched for"))'br4n6 export collects a single correlated timeline from a profile or home
directory and writes it in the format an analyst wants:
# XLSX workbook (one Timeline sheet), timestamps in the examiner's timezone
br4n6 export /mnt/evidence/Users/jsmith \
--format xlsx -o timeline.xlsx --timezone America/New_York --interpret
# SQLite database with a single `timeline` table for ad-hoc SQL
br4n6 export /mnt/evidence/Users/jsmith --format sqlite -o timeline.sqliteFormats: xlsx, sqlite (both require -o FILE), and streaming jsonl / csv
/ text. --timezone accepts any IANA name for human-facing timestamps.
All commands share the same BrowserEvent envelope:
{
"timestamp_ns": 1700000000000000000,
"browser": "Chromium",
"artifact": "History",
"source": "/path/to/History",
"description": "https://example.com — Example Domain",
"attrs": {
"url": "https://example.com",
"title": "Example Domain",
"visit_count": 3
}
}timestamp_ns is always Unix nanoseconds. artifact is the artifact kind (History, Cookies, Downloads, Bookmarks, Autofill, LoginData, Extensions, Cache, Session, Preferences, LocalStorage, Integrity, Carved, Memory). Web-storage events use LocalStorage with a storage_type attr distinguishing Local Storage, Session Storage, and IndexedDB.
The workspace is layered — each crate has a single responsibility:
forensicnomicon format constants, epoch offsets, SQLite magic,
artifact + embedded-Chromium container catalog
|
browser-forensic-core BrowserEvent, BrowserFamily, ArtifactKind, timestamp conversions
|
┌───┴───────────────────────────────────────────────────┐
│ │
browser-forensic-chrome Chromium / Firefox / Safari browser-forensic-discovery
browser-forensic-firefox artifact parsers profile discovery + embedded-
browser-forensic-safari Chromium container sweep
│
├── browser-forensic-storage Local / Session Storage, IndexedDB (reuses leveldb-forensic)
├── browser-forensic-integrity history clearing, visit-ID gaps, WAL detection, timestamp anomalies
├── browser-forensic-carve SQLite free-page + WAL recovery (delegates to sqlite-forensic)
├── browser-forensic-interpret search-term / tracking-cookie / query-string interpretation
└── browser-forensic-memory byte-pattern URL/cookie scanning
|
browser-forensic-triage TriageReport orchestration — wires all crates into one report
|
browser-forensic-cli `br4n6` — dual-mode binary: scriptable CLI + interactive TUI
browser-forensic-mcp `browser-forensic-mcp` — history/state MCP server for AI agents
(PII-redacted; never reads cookies, passwords, or autofill)
Each library crate is independently usable in your own Rust tooling. browser-forensic-integrity, browser-forensic-carve, and browser-forensic-memory accept Path or &[u8] — they are medium-agnostic and have no dependency on any image format or memory-dump layer.
| Crate | Description |
|---|---|
browser-forensic-core |
Domain types, timestamp conversions, ForensicMeta lookups |
browser-forensic-chrome |
Chromium history, cookies, downloads, bookmarks, autofill, login data, extensions, cache, session, Local State, preferences |
browser-forensic-firefox |
Firefox history, cookies, downloads, bookmarks, autofill, extensions, session (mozLz4), login data, preferences |
browser-forensic-safari |
Safari history, cookies, downloads, bookmarks, extensions, TopSites |
browser-forensic-discovery |
Browser profile discovery plus embedded-Chromium container sweep (macOS, Linux, Windows) |
browser-forensic-storage |
Web storage — Local / Session Storage and IndexedDB (Chromium via leveldb-forensic, Firefox via SQLite) |
browser-forensic-integrity |
History clearing, visit-ID gaps, timestamp anomalies, WAL presence, tombstones |
browser-forensic-carve |
SQLite free-page carving and WAL frame recovery (via sqlite-forensic) |
browser-forensic-interpret |
Google-search, tracking-cookie, and query-string interpretation |
browser-forensic-memory |
Byte-pattern URL/cookie scanning for memory forensics |
browser-forensic-triage |
triage_profile() + triage() → TriageReport |
browser-forensic-cli |
br4n6 — scriptable text/JSONL/CSV CLI plus an interactive vi-keyed terminal viewer (br4n6 tui) |
browser-forensic-mcp |
browser-forensic-mcp — an MCP server exposing history/state to AI agents, with PII redaction and no secret readers |
[dependencies]
browser-forensic-chrome = { git = "https://github.com/SecurityRonin/browser-forensic" }
browser-forensic-integrity = { git = "https://github.com/SecurityRonin/browser-forensic" }
browser-forensic-carve = { git = "https://github.com/SecurityRonin/browser-forensic" }use browser_forensic_chrome::parse_history;
use browser_forensic_integrity::{check_history_integrity, IntegrityIndicator};
use browser_forensic_core::BrowserFamily;
let events = parse_history(path)?;
let indicators = check_history_integrity(path, BrowserFamily::Chromium)?;
for ind in &indicators {
match ind {
IntegrityIndicator::HistoryCleared { detected_at_ns, .. } => {
eprintln!("History was cleared at {detected_at_ns}");
}
IntegrityIndicator::VisitIdGap { expected_id, found_id, .. } => {
eprintln!("Visit ID gap: expected {expected_id}, found {found_id}");
}
_ => {}
}
}Browser databases are evidence. This suite is built to read them without altering them and without trusting their contents:
- Read-only on evidence — SQLite databases are opened read-only; the tool never writes back to the artifact, so timestamps and free pages stay intact for re-examination.
forbid(unsafe)— the entire workspace deniesunsafecode at compile time. Malformed, attacker-controlled artifacts cannot reach a raw pointer path.- Panic-free parsers —
clippy::unwrap_used/expect_usedare denied in production code; length and offset fields from the artifact are bounds-checked before use. - Fuzzed —
cargo-fuzztargets cover the Firefox session, SQLite history, carving, integrity, and forensic-catalog paths; every target is built and smoke-run in CI (fuzz.yml). - Coverage gate — CI enforces a line-coverage floor via
cargo llvm-cov; the uncovered remainder is the irreducible imperative shell of the binaries. - CI on Linux, macOS, and Windows — every push runs
cargo fmt --check,cargo clippy -D warnings, build, and the full test suite on all three platforms. - Supply-chain gate —
cargo-denychecks licenses, RustSec advisories, and banned dependencies on every push (deny.toml).
browser-forensic is one parser library in the RapidTriage DFIR toolkit:
| Crate | Artifact family |
|---|---|
| browser-forensic | Chrome / Firefox / Safari + embedded Chromium |
| winevt-forensic | Windows Event Logs (EVTX) |
| srum-forensic | Windows SRUM / ESE |
| memory-forensic | Process memory, page tables |
| forensicnomicon | Artifact catalog, format constants |
Privacy Policy · Terms of Service · © 2026 Security Ronin Ltd