{"schema":"threatline.record/2","record":{"id":"GHSA-633h-mqjc-8rwg","aliases":["GHSA-633h-mqjc-8rwg"],"summary":"gix-pack: reachable assertion panic on valid pack version 3 header aborts clone/fetch","details":"## Summary\r\ngix-pack's pack-header decoder explicitly accepts pack version 3 (returning `Ok((Version::V3, num_objects))`), but the very next step asserts the version equals 2 with `assert_eq!` — which is compiled into release builds. A malicious remote that sends a 12-byte pack header declaring version 3 triggers a panic that aborts the clone/fetch. This is a trivial, deterministic, pre-authentication remote denial of service that fires on every clone/fetch.\r\n\r\n## Root Cause\r\n`data::header::decode` (gix-pack/src/data/header.rs:12-21):\r\n```rust\r\nlet kind = match crate::read_u32(&data[ofs..ofs + N32_SIZE]) {\r\n    2 => data::Version::V2,\r\n    3 => data::Version::V3,          // version 3 is ACCEPTED, not an error\r\n    v => return Err(decode::Error::UnsupportedVersion(v)),\r\n};\r\n```\r\nThen `BytesToEntriesIter::new_from_header` (gix-pack/src/data/input/bytes_to_entries.rs:58):\r\n```rust\r\nlet (version, num_objects) = crate::data::header::decode(&header_data)?;\r\nassert_eq!(\r\n    version,\r\n    crate::data::Version::V2,\r\n    \"let's stop here if we see undocumented pack formats\"\r\n);\r\n```\r\n`assert_eq!` (unlike `debug_assert_eq!`) is NOT compiled out in release. Note the same file uses `debug_assert_eq!` at line 133, confirming the line-58 hard assert is a distinct, deliberate release-time panic. The author's own message (\"let's stop here\") shows an intent to stop gracefully, but a panic was chosen instead of an error return.\r\n\r\n## Impact\r\nThe crate is built with `panic = \"unwind\"` and there is no `catch_unwind` in the runtime read path, so the panic unwinds to the fetch/clone caller → operation/process abort = DoS. It runs first-thing on every clone/fetch (both thin and non-thin branches), before any negotiation-specific state.\r\n\r\n## Proof of Concept\r\nServe a pack stream beginning `50 41 43 4B 00 00 00 03 <num_objects>` (\"PACK\", version 3) to a victim `gix clone`/`fetch`. `header::decode` returns `Ok((V3, ...))`, then the `assert_eq!(version, V2)` panics.\r\n\r\n## Attack Chain\r\n1. Entry: attacker serves a pack beginning `50 41 43 4B 00 00 00 03 ...`. Guard: `header::decode` version check. Bypass proof: header.rs:14 returns `Ok(Version::V3, ...)` for byte value 3; only versions ≠ 2,3 error.\r\n2. Sink: `new_from_header` runs `assert_eq!(version, V2)` (bytes_to_entries.rs:58). Guard: should be a graceful `UnsupportedVersion` error. Bypass proof: it is `assert_eq!` (not `debug_assert_eq!`) → panics on V3 in release.\r\n3. Impact: panic on the fetch/clone thread → process/operation abort = remote DoS. 12 attacker bytes, no negotiation state, no thin-pack precondition.\r\n\r\n## Bypass Evidence\r\n- `git show gix-pack-v0.74.2:gix-pack/src/data/header.rs` confirms version 3 → `Ok(Version::V3, ...)` on the latest tag.\r\n- `git show gix-pack-v0.74.2:gix-pack/src/data/input/bytes_to_entries.rs` confirms the `assert_eq!(version, Version::V2, ...)` at line 58 (and `debug_assert_eq!` at line 133, proving the distinction is deliberate).\r\n- The GHSA-x494-mj8g-cj27 panic-fix commits b69f0a6a/5850141e edited only `data/entry/decode.rs`; this pack-header assert is untouched.\r\n\r\n## Affected Versions\r\n`gix-pack <= 0.74.2` (latest release tag gix-pack-v0.74.2; code present on HEAD). No post-tag fix.\r\n\r\n## Suggested Fix\r\nReturn a graceful `decode::Error::UnsupportedVersion`/dedicated error for any non-V2 version in `new_from_header` instead of `assert_eq!`.\r\n\r\n---\r\nReported by **zx (Jace)** — GitHub: @manus-use","categories":["Unclassified"],"product":"gix-pack","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-633h-mqjc-8rwg","source_modified_at":"2026-09-25T08:30:52Z","fetched_at":"2026-10-23T20:00:35.122048Z","package":{"ecosystem":"other","name":"gix-pack"},"range":"<= 0.74.2"}],"fixed_versions":[],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-09-25T08:30:52Z","modified_at":"2026-09-25T08:30:52Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-633h-mqjc-8rwg","fetched_at":"2026-10-23T20:00:35.122048Z","source_modified_at":"2026-09-25T08:30:52Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-09-25T08:30:52Z","content_hash":"37cd86a764b9b317ef984299e0626493cc9198ba23b7f20a9b6897a125985433"}}
