{"id":51015066,"url":"https://github.com/securityronin/snss-forensic","last_synced_at":"2026-06-21T09:02:38.139Z","repository":{"id":365133112,"uuid":"1270195615","full_name":"SecurityRonin/snss-forensic","owner":"SecurityRonin","description":"Chromium/Brave/Edge SNSS session-file forensic decoder — panic-free, read-only; validates the SNSS command stream, decodes navigation base::Pickle payloads, replays per-window tab state. No runtime deps.","archived":false,"fork":false,"pushed_at":"2026-06-16T01:46:22.000Z","size":48,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T03:20:56.901Z","etag":null,"topics":["brave","browser-forensics","chrome","chromium","dfir","digital-forensics","forensics","incident-response","rust","session-restore","snss"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SecurityRonin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T13:30:05.000Z","updated_at":"2026-06-16T01:46:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SecurityRonin/snss-forensic","commit_stats":null,"previous_names":["securityronin/snss-forensic"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/SecurityRonin/snss-forensic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fsnss-forensic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fsnss-forensic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fsnss-forensic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fsnss-forensic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SecurityRonin","download_url":"https://codeload.github.com/SecurityRonin/snss-forensic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fsnss-forensic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34603641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-21T02:00:05.568Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["brave","browser-forensics","chrome","chromium","dfir","digital-forensics","forensics","incident-response","rust","session-restore","snss"],"created_at":"2026-06-21T09:02:36.285Z","updated_at":"2026-06-21T09:02:38.120Z","avatar_url":"https://github.com/SecurityRonin.png","language":"Rust","funding_links":["https://github.com/sponsors/h4x0r"],"categories":[],"sub_categories":[],"readme":"# snss-forensic\n\n[![snss-core](https://img.shields.io/crates/v/snss-core.svg?label=snss-core)](https://crates.io/crates/snss-core)\n[![Docs.rs](https://img.shields.io/docsrs/snss-core?label=docs.rs)](https://docs.rs/snss-core)\n[![Rust 1.81+](https://img.shields.io/badge/rust-1.81%2B-orange.svg)](https://www.rust-lang.org)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)\n[![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r)\n\n[![CI](https://github.com/SecurityRonin/snss-forensic/actions/workflows/ci.yml/badge.svg)](https://github.com/SecurityRonin/snss-forensic/actions/workflows/ci.yml)\n[![Coverage](https://img.shields.io/badge/coverage-100%25%20lines-brightgreen.svg)](https://github.com/SecurityRonin/snss-forensic/actions/workflows/ci.yml)\n[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)\n[![Security advisories](https://img.shields.io/badge/security-cargo--deny-informational.svg)](deny.toml)\n\n**Chromium/Brave/Edge SNSS session-file forensics for Rust — a panic-free,\nread-only decoder that validates the `SNSS` command stream, splits it into\nlength-prefixed records, decodes navigation-command `base::Pickle` payloads, and\nreplays them into the per-window tab state a browser restores on launch.**\n\nSNSS is the append-only command-log format Chromium-family browsers use to persist\nsession and tab state — the `Session_*`, `Tabs_*`, and `Apps_*` files (and the\nmodern `Sessions/` folder) behind \"restore your tabs\". Each file is a 4-byte\n`SNSS` magic plus a version header, followed by `u16`-length-prefixed command\nrecords; navigation commands carry a Chromium `base::Pickle` payload.\n[`snss-core`](https://crates.io/crates/snss-core) decodes that structure faithfully\nand makes no judgments — no `unsafe`, no C bindings, no write path.\n\n## Read a session file in 30 seconds\n\n```toml\n[dependencies]\nsnss-core = \"0.1\"\n```\n\n```rust\nuse std::io::Cursor;\n\n// 1. Validate the SNSS header and split the command stream into records.\nlet stream = snss::read_records(Cursor::new(bytes))?;\n\n// 2. Replay the commands into the per-window tab tree the browser would restore.\nlet replayed = snss::replay(\u0026stream, snss::Dialect::Session);\nfor window in \u0026replayed.windows {\n    for tab in \u0026window.tabs {\n        let nav = tab.current_nav();   // the current entry of each open tab\n        println!(\"tab {} -\u003e {}  ({})\", tab.id, nav.url, nav.title);\n    }\n}\n\n// Non-fatal anomalies (a truncated live-file tail, a bad navigation Pickle) are\n// surfaced, never silently dropped:\nfor w in \u0026stream.warnings { eprintln!(\"{w:?}\"); }\n# Ok::\u003c(), snss::SnssError\u003e(())\n```\n\n`Tabs_*` files (the recently-closed restore list) use the `Tabs` dialect; pass\n`snss::Dialect::Tabs`. To walk every session source in a profile directory at\nonce, use `snss::SessionStore::open_dir(profile_dir)` (or\n`open_default_profile()`), which reads each source and keeps per-source warnings.\n\n## What it decodes\n\n| Entry point | Reads | Produces |\n|---|---|---|\n| `read_records` | `SNSS` magic + version header, `u16`-length records | `RecordStream { version, records, warnings }` |\n| `decode_navigation` | a navigation command's `base::Pickle` payload | `NavCommand { tab_id, index, url, title }` |\n| `replay` | a `RecordStream` + dialect | `Replayed { windows }` — `Window`/`Tab`/`Nav` tree |\n| `SessionStore::open_dir` | a profile directory | every discovered `Source` + warnings |\n\nThe `base::Pickle` decoder is 4-byte-aligned and length-prefixed exactly as\nChromium writes it (UTF-8 URLs, UTF-16-LE titles); replay applies last-write-wins\nper `(tab, index)` and resolves each tab's current entry and pinned state.\n\n## Trust but verify\n\nSNSS files are untrusted, attacker-controllable input, so the crate is hardened\nby construction:\n\n- **`#![forbid(unsafe_code)]`** across the whole workspace — no `unsafe`, anywhere.\n- **Read-only by construction** — the decoder exposes **no write path**; mutating\n  a browser's session store is structurally impossible through this API.\n- **Panic-free** — every record length, Pickle field length, and alignment step\n  is bounds-checked before use; a crafted length field cannot drive an\n  out-of-bounds read or an allocation bomb. Malformed input surfaces as a typed\n  `SnssError` or a non-fatal `Warning`, never a silent default.\n- **Fuzzed** — `cargo-fuzz` targets cover the record-stream reader (`records`) and\n  the navigation `base::Pickle` decoder (`navigation`); the invariant is \"must not\n  panic.\"\n- **Validated against real Chromium data** — real Brave `Session_*`/`Tabs_*`/`Apps_*`\n  files are read and replayed (the fixtures are gitignored — they hold personal\n  history), alongside byte-exact synthetic command streams. See\n  [`docs/validation.md`](docs/validation.md).\n\n## Planned: the `snss-forensic` analyzer\n\nThis workspace ships the reader (`snss-core`) today. A sibling `snss-forensic`\nanalyzer crate — emitting severity-graded\n[`forensicnomicon::report`](https://crates.io/crates/forensicnomicon) findings for\nsession-restore anomalies (e.g. dangling or forward-referenced tab indices,\ntruncated-tail recovery, replay inconsistencies) — is a planned follow-up so a\nsession file's anomalies aggregate uniformly with every other artifact layer. No\nanalyzer logic exists yet; it is not stubbed or fabricated here.\n\n## References\n\n- **Chromium `components/sessions`** — the canonical SNSS writer/reader (command\n  framing, `SNSS` magic + version header, append-only log):\n  \u003chttps://source.chromium.org/chromium/chromium/src/+/main:components/sessions/core/command_storage_backend.cc\u003e\n- **Chromium `base::Pickle`** — the field-encoding format navigation payloads use:\n  \u003chttps://source.chromium.org/chromium/chromium/src/+/main:base/pickle.h\u003e\n\n---\n\n[Privacy Policy](https://securityronin.github.io/snss-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/snss-forensic/terms/) · © 2026 Security Ronin Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fsnss-forensic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecurityronin%2Fsnss-forensic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fsnss-forensic/lists"}