{"id":51015051,"url":"https://github.com/securityronin/cfb-forensic","last_synced_at":"2026-06-21T09:02:33.391Z","repository":{"id":365068309,"uuid":"1268464766","full_name":"SecurityRonin/cfb-forensic","owner":"SecurityRonin","description":"OLE/CFB ([MS-CFB]) forensic analyzer — carves compound files for orphaned (deleted) directory entries, free-sector + slack residue, and structural tamper tells. Panic-free, no unsafe, fuzzed.","archived":false,"fork":false,"pushed_at":"2026-06-15T17:38:05.000Z","size":636,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T19:26:50.578Z","etag":null,"topics":["carving","cfb","compound-file","dfir","digital-forensics","forensics","incident-response","jumplist","ole","rust"],"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-13T15:07:33.000Z","updated_at":"2026-06-15T17:37:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SecurityRonin/cfb-forensic","commit_stats":null,"previous_names":["securityronin/cfb-forensic"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/SecurityRonin/cfb-forensic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fcfb-forensic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fcfb-forensic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fcfb-forensic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fcfb-forensic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SecurityRonin","download_url":"https://codeload.github.com/SecurityRonin/cfb-forensic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SecurityRonin%2Fcfb-forensic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34603629,"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":["carving","cfb","compound-file","dfir","digital-forensics","forensics","incident-response","jumplist","ole","rust"],"created_at":"2026-06-21T09:02:32.350Z","updated_at":"2026-06-21T09:02:33.386Z","avatar_url":"https://github.com/SecurityRonin.png","language":"Rust","funding_links":["https://github.com/sponsors/h4x0r"],"categories":[],"sub_categories":[],"readme":"# cfb-forensic\n\n[![cfb-forensic](https://img.shields.io/crates/v/cfb-forensic.svg)](https://crates.io/crates/cfb-forensic)\n[![Docs.rs](https://img.shields.io/docsrs/cfb-forensic)](https://docs.rs/cfb-forensic)\n[![Rust 1.81+](https://img.shields.io/badge/rust-1.81%2B-blue.svg)](https://www.rust-lang.org)\n[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)\n[![CI](https://github.com/SecurityRonin/cfb-forensic/actions/workflows/ci.yml/badge.svg)](https://github.com/SecurityRonin/cfb-forensic/actions)\n[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)\n[![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r)\n\n**Carve OLE Compound File Binary ([MS-CFB]) files for what a happy-path reader hides — orphaned (deleted) directory entries, free-sector and slack residue, and structural tamper tells.**\n\nCFB (a.k.a. OLE2 / COM Structured Storage) is the container behind JumpLists (`.automaticDestinations-ms`), legacy Office `.doc`/`.xls`/`.ppt`, `.msi`, `.msg`, thumbcache, and sticky notes. The mature [`cfb`](https://crates.io/crates/cfb) crate reads the *live* streams and storages perfectly; it does **not** expose the deleted-stream metadata, unallocated sectors, or marker violations that matter to an examiner. `cfb-forensic` adds exactly that carving layer on top — the CFB analogue of `sqlite-forensic` over `rusqlite`.\n\n## Audit a compound file in 30 seconds\n\n```toml\n[dependencies]\ncfb-forensic = \"0.1\"\n```\n\n```rust\nuse cfb_forensic::audit_bytes;\n\nfor finding in audit_bytes(compound_file_bytes) {\n    println!(\"{finding:?}\");   // OLECF-ORPHANED-DIR-ENTRY, OLECF-FREE-SECTOR-RESIDUE, ...\n}\n```\n\n`audit_bytes` does a minimal raw walk of the header, FAT/mini-FAT and directory — independent of `cfb`'s logical view — so it can see sectors and directory entries the navigation layer has already discarded.\n\n## What it observes\n\n| Code | What it observes |\n|---|---|\n| `OLECF-ORPHANED-DIR-ENTRY` | a directory entry unreachable from the root red-black tree — recoverable **deleted-stream** name, size and content pointer |\n| `OLECF-FREE-SECTOR-RESIDUE` | a FAT/mini-FAT sector marked free (`FREESECT`) that still holds non-zero bytes — deleted-stream remnants |\n| `OLECF-SLACK-RESIDUE` | non-zero bytes past a stream's declared size, in its final allocated sector |\n| `OLECF-STRUCTURE-ANOMALY` | a marker / DIFAT / red-black violation, or a stream entry carrying a non-zero CLSID or timestamps ([MS-CFB] says those MUST be zero for a stream — a tamper tell) |\n| `OLECF-ROOT-CLSID` | the root-storage CLSID and the only creation/modification timestamps CFB records |\n\nEvery finding is a `forensicnomicon::report` observation — **\"consistent with\", never a verdict**; the analyst concludes. Format constants (signature, sector markers, directory-entry offsets, `ObjectType`/`Color` enums) come from [`forensicnomicon::olecf`](https://crates.io/crates/forensicnomicon).\n\n## Trust but verify\n\nPanic-free on untrusted input — every offset, sector index and length field is range-checked before use, allocations are capped, and the raw walk never indexes a slice unchecked. `#![forbid(unsafe_code)]`, fuzzed over `audit_bytes`, validated against real compound files (JumpLists and `.msi`/`.msg` samples). The happy-path read path is the battle-hardened `cfb` crate (40M+ downloads since 2017); we add only the carving walk.\n\n---\n\n[Privacy Policy](https://securityronin.github.io/cfb-forensic/privacy/) · [Terms of Service](https://securityronin.github.io/cfb-forensic/terms/) · © 2026 Security Ronin Ltd\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fcfb-forensic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecurityronin%2Fcfb-forensic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecurityronin%2Fcfb-forensic/lists"}