Skip to content

gix-transport: CR/LF/NUL injection into git-daemon connect request via crafted git:// URL path

Moderate
Byron published GHSA-rc7h-wp5f-w3g5 Sep 1, 2026

Software

gix-transport

Affected versions

<= 0.59.1

Patched versions

>= 0.59.2

Description

Summary

gix-transport builds the git-daemon connect request line by writing the URL path and host with no control-character filtering. Because the URL parser validates the still-percent-encoded input and the subsequent percent-decode accepts NUL/CR/LF (all valid UTF-8), an attacker who controls part of a git:// URL can inject raw NUL/CR/LF bytes into the daemon request — smuggling extra NUL-delimited protocol fields (e.g. an attacker-chosen host= virtual-host) into the git pack-protocol connect line.

Root Cause

message::connect (gix-transport/src/client/git/mod.rs:28-49) writes path and host into the git-daemon request git-upload-pack <path>\0host=<host>\0… using extend_from_slice/push_str with zero control-char filtering. Both derive from a parsed git:// URL:

  • ParsedUrl::parse (gix-url/src/parse/simple_url.rs:107) performs its only control-char guard (is_whitespace / has_valid_percent_encoding) on the still-ENCODED string, so %00/%0A/%0D pass (valid percent-encoding, no whitespace).
  • percent_decode (simple_url.rs:53-58) only errors on invalid UTF-8; NUL/CR/LF are valid UTF-8 and survive into the decoded path.
  • connect.rs:53-56 hands the decoded url.path to the daemon connect(), which flows verbatim into message::connect.

Impact

The confirmed primitive is PATH-based injection. Injected content lands in the git pack-protocol's documented NUL-delimited extra-parameters region (host=…), enabling git-daemon virtual-host spoofing (daemon serves an attacker-chosen vhost/repo) and raw newline injection into the request/logs. The HOST sub-vector is self-defeating (a NUL in host breaks (host, port).to_socket_addrs() before the request is built), so only the path vector is live.

Proof of Concept

git://real.example/repo%00host=evil.example%00 — via a malicious .gitmodules submodule URL, a hosting layer that concatenates a trusted host with an attacker-controlled path, or a MITM. ParsedUrl::parse accepts it; the path decodes to /repo\0host=evil.example\0; message::connect emits git-upload-pack /repo\0host=evil.example\0\0host=real.example\0, so the injected host=evil.example field precedes the legitimate one.

Attack Chain

  1. Entry: victim uses git://real.example/repo%00host=evil.example%00 (malicious submodule URL / hosting concatenation / MITM). Guard: ParsedUrl::parse whitespace/percent check (simple_url.rs:107). Bypass proof: the check sees literal ASCII %00 (valid percent-encoding, no whitespace) → passes.
  2. Processing: percent_decode_path decodes to /repo\0host=evil.example\0 (simple_url.rs:142). Guard: post-decode control-char rejection. Bypass proof: percent_decode (simple_url.rs:53-58) only errors on invalid UTF-8; NUL/CR/LF are valid UTF-8 → survive.
  3. Sink: message::connect emits git-upload-pack /repo\0host=evil.example\0\0host=real.example\0 (git/mod.rs:37-47). Guard: control-char validation in the writer (the same guard the credential-helper CR/LF fix, GHSA-6wr8-3w4h-j9wj, added for its own context). Bypass proof: git/mod.rs:37-44 calls extend_from_slice/push_str with no filtering.
  4. Impact: git-daemon parses the extra NUL-delimited host= field → virtual-host spoofing; %0A/%0D inject raw newlines into the request/logs.

Bypass Evidence

  • git show gix-transport-v0.59.1:gix-transport/src/client/git/mod.rs confirms message::connect writes path/host with no filtering on the latest tag.
  • simple_url.rs:107 runs the guard on encoded input; simple_url.rs:53-58 percent_decode returns Ok for \0/\r/\n.
  • The credential-helper CR/LF fix (commit 3a99e25) is confined to gix-credentials/.../serde.rs::validate — it does not cover this serializer. Same accepted class as GHSA-6wr8-3w4h-j9wj (gitoxide credential helper bare-CR) and existing gix-transport URL-component injection advisories.

Affected Versions

gix-transport <= 0.59.1 (latest release tag gix-transport-v0.59.1; code present on HEAD).

Suggested Fix

Reject control characters (NUL/CR/LF) in the path and host before writing the git-daemon connect request, and/or reject decoded control characters during URL parsing.


Reported by zx (Jace) — GitHub: @manus-use

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N

CVE ID

CVE-2026-91986

Weaknesses

Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')

The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component. Learn more on MITRE.

Improper Neutralization of CRLF Sequences ('CRLF Injection')

The product uses CRLF (carriage return line feeds) as a special element, e.g. to separate lines or records, but it does not neutralize or incorrectly neutralizes CRLF sequences from inputs. Learn more on MITRE.

Credits