zip-forensic
Audit a ZIP for tampering, and read every common codec — in pure Rust, with zero C-FFI dependencies.
// Surface where an archive's central directory disagrees with its local headers —
// the classic post-hoc-edit signal a happy-path reader silently trusts.
for anomaly in audit_path?
// [High] ZIP-CD-LFH-MISMATCH: entry 3 (report.docx): central-directory crc32
// (0x1a2b3c4d) disagrees with the local file header (0x00000000) — consistent
// with a post-hoc edit of one copy
That's it — point it at a zip and read graded findings. Each is an observation
("consistent with"), never a verdict, and converts to a
forensicnomicon Finding.
Read entries without the C libraries
zip-forensic-core parses the container and decodes every common method with only
pure-Rust crates — the three C libraries the popular zip crate pulls
(bzip2-sys, zstd-sys, lzma-sys) are gone:
use Read;
let mut archive = new?;
let mut entry = archive.by_name?; // Stored/Deflate/Deflate64/Bzip2/Zstd/LZMA/XZ
let mut bytes = Vecnew;
entry.read_to_end?; // CRC-32 verified on EOF; fails loud on mismatch
$ cargo tree -p zip-forensic-core -e normal | grep -- -sys
$ # empty — no C-FFI in the runtime tree
Encrypted entries decrypt with a password — traditional ZipCrypto and WinZip AES (128/192/256), the latter on audited RustCrypto with HMAC verification:
let mut entry = archive.by_name_decrypt?;
// plain by_name() refuses an encrypted entry — secure by default
Random-access a disk image inside a zip — no extraction
A forensic image stored in a ZIP at ~0% compression is, at the deflate level, a
run of byte-aligned stored blocks. zip-forensic-core indexes them so any offset is
addressable directly, with no full inflation and no temp spill:
let entry = open_entry?;
let mut buf = vec!;
entry.read_at?; // positioned read, lock-free, no decompression from start
Install
[]
= "0.1" # the reader
= "0.1" # the auditor
Safety
#![forbid(unsafe_code)], panic-free on untrusted input (bounds-checked reads,
entry-count and decompression-bomb caps), enclosed_name() refuses
path-traversal names, and three cargo-fuzz targets assert the parser, decoder,
and audit pipeline never panic. Correctness is established against independent
oracles — see the validation notes.
Privacy Policy · Terms of Service · © 2026 Security Ronin Ltd