Repository navigation
fix(deps): bump zip 2.4.2 -> 9.1.2 for zip2 CVEs - #1580
Conversation
zip <= 9.0.4 is affected by CVE-2026-115905/-115907/-115908/-115909. Only the pre-seed feature uses zip; call sites compile unchanged. Closes openabdev#1579 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B3XpFuLNuKJRyvvTT35Mka
This comment has been minimized.
This comment has been minimized.
Addresses review findings F1/F2 on the zip 2.4.2 -> 9.1.2 bump. - zip: use `deflate-flate2` instead of `deflate`. zip 9's `deflate` enables `flate2/zlib-rs`, which via feature unification switched the flate2 backend for both zip and tar.gz (`GzDecoder`) extraction from miniz_oxide to zlib-rs. `deflate-flate2` selects no backend, so the existing `flate2 = "1"` default (miniz_oxide) stays in effect. Drops `zlib-rs` and the write-only `zopfli` from the lockfile. - pre_seed: zip 9's `enclosed_name()` strips a leading `/` and accepts absolute entry names that zip 2.x rejected. Reject entries whose raw name starts with `/` or `\` so such archives keep failing closed. - test: `extract_rejects_path_traversal` covers `../`, nested `../../`, `/abs` and `\abs`, asserting rejection and that nothing is written. Verified it fails on main's zip 2.4.2 only for cases it newly pins.
|
Pushed 0d9ac3b on top of your commit to address F1 and F2 (maintainer edit, no force-push). F1: flate2 backend. Switched to F2: traversal test, plus one behaviour change it exposed. zip 9's A correction to the commit body: its last line says the test fails on main. That is not right for the final version. With the explicit reject, every case is also rejected on zip 2.4.2, so the test passes on main and pins the 2.x contract across the bump. It failed on main only in an earlier draft that asserted the 9.x strip behaviour. Verified on macOS arm64:
Still with you (description only), F3:
|
This comment has been minimized.
This comment has been minimized.
|
/review |
Regenerate from main's lockfile with `cargo update -p zip --precise 9.1.2` so the diff touches only zip and its transitive deps. The previous regeneration downgraded unrelated windows-sys / getrandom edges (F8).
|
Round 2 addressed:
/review |
|
/review |
|
Note LGTM ✅ - Round 3: every finding is resolved. What This PR Does
How It Works
Findings Status
Findings (Round 3)
Non-blocking Notes
Addressing Feedback on This PR
Agent Team Verdicts
Devil's Advocate: Three Reasons We Might Not Need This PR
Baseline Check
What's Good (🟢)
|
There was a problem hiding this comment.
LGTM ✅ - Round 3: all findings (F1, F2, F3, F8) resolved; zip 9.1.2 bump keeps the miniz_oxide backend, fails closed on root-anchored entry names, and the lockfile diff vs main is limited to zip.
Full review: #1580 (comment)
Please confirm CI is green on 2171842 before merging.
thepagent
left a comment
There was a problem hiding this comment.
LGTM. Round 3 bot review clean, all checks green. Approving as code owner.
Brings in openabdev#1578 (MCP facade served stateless — a 5-min idle session no longer 404s and, with Claude Code's reconnect, no longer risks duplicating non-idempotent writes) and openabdev#1580 (zip 2.4.2 -> 9.1.2 for zip2 CVEs). facade.rs is touched on both sides but in disjoint regions (upstream: serve_http/build_router; downstream: facade_tools/ServerHandler + tests). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What problem does this solve?
openab-coreresolveszip2.4.2. Several zip-rs/zip2 advisories cover that version, including CVE-2026-115905 (critical, "Dual-Header Inconsistencies / Zip Cloaking") and GHSA-wjr6-mhvj-cjvm (ZipArchive::newEOCD fallback). The table below lists all of them. The crate is used only by thepre-seedfeature, which is on by default in the root binary. That feature parses archive bytes downloaded from S3 withzip::ZipArchive::new.Closes #1579
Discord Discussion URL: https://discord.com/channels/1491295327620169908/1491365158868619404/1564673005240451224
Review Contract
Goal
Move
zipto a fixed release (9.1.2) and keeppre_seedzip extraction behaviour as close to 2.4.2 as possible: same flate2 backend (miniz_oxide), and escaping or root-anchored entry names are still rejected. The two remaining zip 9 path differences are listed under Accepted Residual Risks.Non-goals
pre_seedextraction semantics (limits, permissions, overwrite).size(). That is a separate concern from this advisory and goes in a follow-up issue.Accepted Residual Risks
pre_seed.rsuses (ZipArchive::new,by_index,enclosed_name,name_raw,is_dir,size,unix_mode) compile, and thepre_seedtests pass. Path handling is now pinned byextract_rejects_path_traversal. Edge-case archives outside the tests could still behave differently. Recovery is to revert this squash commit.enclosed_name()normalises two cases differently from 2.x, and both stay insidedest:\is treated as a path separator, soa\b.txtextracts todest/a/b.txtinstead of a flat file nameda\b.txt.C:/xextracts todest/x. On 2.x under Unix it extracted todest/C:/x.Rejecting drive prefixes would be a new restriction rather than parity, so it is left as is.
rust:1-bookwormand CI'sbuild-builderand smoke tests are green. A builder pinned to an older toolchain would fail at build time, not at runtime.Acceptance Criteria
Cargo.lockresolveszip9.1.2. Compared withmain, the lockfile diff is limited to zip's transitive deps: it removesarbitrary,crossbeam-utils,derive_arbitraryandzopfli, and addstyped-path. The only new edges are zip's own (getrandom 0.4.3,nix,typed-path,windows-sys 0.61.2) plusgetrandom 0.4.3's wasm32-onlyjs-sys/wasm-bindgen. No unrelated crate edges change.flate2still depends onminiz_oxide, andzlib-rsis not in the lockfile.../x,a/../../x,/xand\xare rejected, and nothing is written (extract_rejects_path_traversal). The test passes on both zip 2.4.2 and 9.1.2.cargo clippy --all-targets -- -D warningsis clean.cargo clippy --workspace --features unified -- -D warningsis clean.pre_seedtests pass (cargo test -p openab-core --features pre-seed pre_seed).cargo test --bin openabpasses.Follow-ups
size()(low priority: zip >= 9.0.1 already fails reads that exceed the declared size, fix: fail reads that exceed the declared uncompressed size zip-rs/zip2#1022).cargo audit/cargo denyto CI (separate PR).At a Glance
Advisory coverage
pre_seedbuilds zip withdefault-features = false, features = ["deflate-flate2"](no AES, nolegacy-zip). It reads entries only throughZipArchive::new+by_index+std::io::copy. It never callsZipArchive::extract()orZipStreamReader, it never creates symlinks from zip entries, and it masks modes to0o777.pre_seed?by_indexZipArchive::newEOCD fallbackZipArchive::newpre_seedcreates no symlinksextract()applies perms through symlinksextract()onlyextract()symlinks outside destextract()onlypre_seedmasks to0o777legacy-zipnot enabledextract()lexical symlink checkextract()onlySource:
gh api repos/zip-rs/zip2/security-advisories(2026-10-27).Prior Art & Industry Research
Not applicable. This is a security dependency bump with no design change.
Proposed Solution
crates/openab-core/Cargo.toml:zip = { version = "9.1.2", default-features = false, features = ["deflate-flate2"], optional = true }, thencargo update -p zip --precise 9.1.2.deflatefeature turns onflate2/zlib-rs. Through Cargo feature unification that would switch the flate2 backend for both zip and the tar.gz (GzDecoder) path fromminiz_oxidetozlib-rs.deflate-flate2pulls in flate2 without picking a backend, so the existingflate2 = "1"default (miniz_oxide) stays in effect. It also drops the write-onlyzopfli.pre_seed.rs: in zip 9,enclosed_name()strips a leading root, so/abs.txtwould extract todest/abs.txt. zip 2.x rejected that entry name. The new check rejects raw names that start with/or\before callingenclosed_name(), so these archives still fail closed.extract_rejects_path_traversalpins the contract.Cargo.lockis regenerated frommainwithcargo update -p zip --precise 9.1.2only.Why this approach?
ZipArchive::new, which is the exact entry pointpre_seeduses. GHSA-gmfj-vffv-32pw is also fixed in 9.1.0."9.1.2"means^9.1.2. Later 9.x security patches are picked up, and the vulnerable 9.0.0–9.0.5 releases are excluded.Alternatives Considered
9.0.5: it misses GHSA-wjr6-mhvj-cjvm, which reachesZipArchive::new.features = ["deflate"]and documenting thezlib-rsswitch: rejected, because it silently changes the decompressor for untrusted S3 bytes on both archive formats.zipor dropping.zipsupport frompre_seed: a larger change, not justified here.Validation
macOS arm64, rustc 1.99.1, head
2171842:cargo clippy --all-targets -- -D warnings: cleancargo clippy --workspace --features unified -- -D warnings: cleancargo test -p openab-core --features pre-seed pre_seed: 34 passed, 0 failed (includes the newextract_rejects_path_traversal)cargo test --bin openab: 18 passed, 0 failedCargo.lock:flate2 1.1.9depends oncrc32fastandminiz_oxide; nozlib-rsand nozopflipackages.Originally authored by @dogzzdogzz; F1/F2/F3 from the round-1 review addressed by maintainers in 0d9ac3b and 2171842.