Coordinated disclosureCVE-2026-77355 · GHSA-6fxm-h49m-4fg3isomorphic-git · npm8.8 High

Proof/CVEs & advisories/CVE-2026-77355

CVE.08 — Published record

The name was checked. NTFS disagreed.

isomorphic-git already rejected .git, case variants, trailing-dot forms and short-name aliases. It accepted .git::$INDEX_ALLOCATION — the one spelling that NTFS resolves back to the real gitdir.

CVECVE-2026-77355
AdvisoryGHSA-6fxm-h49m-4fg3
Packageisomorphic-git
Ecosystemnpm · Node.js
Affected≤ 1.38.6
Fixed1.38.7
Severity8.8 High
ReporterCharles Vosburgh
Reserved-name filtering was present and working. It reasoned about the input spelling instead of what the destination filesystem resolves.
Weakness
CWE-22
Trigger
.git::$INDEX_ALLOCATION
Control
.git and git~1 rejected
Outcome
write inside the live gitdir
Public-safety boundary.The proof of concept is public in GHSA-6fxm-h49m-4fg3. This page documents the failed invariant, the cross-platform controls and the remediation boundary; it does not republish the crafted object stream.

A Git tree entry is untrusted input. During clone or checkout, isomorphic-git parses the tree and writes the corresponding files and directories into the working copy. The active .git directory must stay unreachable from any repository-supplied pathname.

No attacker-controlled tree path may resolve to the active Git metadata directory after platform-specific filesystem namespace transformations.

NTFS supports alternate data streams and stream types. For a directory, ::$INDEX_ALLOCATION identifies the directory’s index-allocation stream — which means a pathname like .git::$INDEX_ALLOCATION can alias the actual .git directory rather than naming an ordinary sibling.

Version 1.38.6 normalized the whole path component before comparing it against the reserved-name list:

Vulnerable normalizationisomorphic-git 1.38.6
const hfsClean = path.replace(
  /[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
  ''
)
const normalized = hfsClean.toLowerCase().replace(/[. ]+$/, '')

For .git::$INDEX_ALLOCATION, the normalized value still carries the colon suffix. It is not equal to .git, so it passes.

The parser behaviour makes an unusually clean control. Exact 1.38.6 rejects literal .git, a case/trailing-space form, and git~1 — while accepting the stream alias. This is not an absence of validation; it is a platform-specific namespace form missing from the equivalence model.

1

Attacker controls the object stream

A crafted tree carries .git::$INDEX_ALLOCATION path components. The clearest threat model is an untrusted or permissive self-hosted remote; some hosted services reject the malicious object first.

2

Victim clones on Windows NTFS

The working directory must be on NTFS for the alias to mean anything.

3

String-level validation accepts the path

The normalized name is not equal to .git, so reserved-name filtering lets it through.

4

NTFS resolves it into the real gitdir

Repository-controlled content is written over trusted Git metadata, including configuration and hook-area content.

5

A later native Git run consumes it

The published follow-on places core.fsmonitor configuration; a subsequent native git status executes the marker.

Attribution precision. The marker executes in the later native Git process, not inside isomorphic-git. The directly demonstrated primitive is the attacker-controlled write into the active gitdir; command execution is the downstream consumer step, and the advisory’s user-interaction metric reflects exactly that.
Negative control

Ordinary reserved names

Exact 1.38.6 rejects .git, case and trailing-space variants, and git~1. Validation is active.

Vulnerable path

NTFS stream alias

Exact 1.38.6 accepts the alias; content lands inside the real gitdir after loopback Smart-HTTP clone.

Fixed control

1.38.7

The alias is rejected. Benign colon-containing names that do not resolve to the gitdir keep working.

CONTROL 1.38.6 rejects .git / .git / git~1: PASS PLATFORM Windows NTFS working directory ACCEPTED .git::$INDEX_ALLOCATION passes reserved-name filter WRITE observed inside the live gitdir CROSS-PLATFORM Linux treats the same path as a literal colon name NATIVE GIT refuses checkout of the crafted path FIXED 1.38.7 rejects the alias: PASS

The validator made a security decision on the lexical pathname before accounting for the destination filesystem’s equivalence rules. NTFS could assign a string that did not compare equal to .git the meaning of the .git directory itself.

The security question is not “does this string equal .git?” It is “after the target filesystem interprets this name, can the destination resolve inside the protected metadata directory?”
The SecHive research loop

The negative controls are what made the claim precise.

An accepted path is only interesting if the surrounding filter is provably working. Four controls separated a namespace gap from a general absence of validation, and separated the library’s write primitive from the consumer’s execution.

SK.01

Source mapping

Locate the reserved-name filter and the exact point where a tree path becomes a filesystem write.

SK.02

Platform hypothesis

Ask what the destination filesystem resolves, not what the string looks like.

SK.03

Differential controls

Prove 1.38.6 rejects ordinary reserved names while accepting the alias; prove Linux does not alias at all.

SK.04

Skeptic gate

Keep the isomorphic-git write and the native-Git execution as two separate claims.

HUMAN

Promotion and disclosure

Confirm the threat model, version boundaries and public-safety limits before reporting.

Version 1.38.7 treats the first colon as the boundary between the NTFS filename and the stream declaration, then applies the existing reserved-name checks:

Fixed normalizationisomorphic-git 1.38.7
const ntfsClean = hfsClean.split(':')[0]
const normalized = ntfsClean.toLowerCase().replace(/[. ]+$/, '')

The fixing commit is e5dbec689fab148fd5b518f3d4958c9d728886f9. The accompanying regression tests reject .git::$INDEX_ALLOCATION, other .git stream forms, case and trailing-dot/space variants, and git~1 stream forms, while retaining benign colon-containing names.

High
Published advisory severity
8.8
CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

User interaction reflects the later consumer step in the demonstrated chain rather than a second independent vulnerability.

ScopeRangeBasis
Public advisory≤ 1.38.6publisher’s stated range
Directly reviewed vulnerable1.38.5, 1.38.6source review of exact npm artifacts
Fixed1.38.7source review plus runtime control

Earlier releases were not individually sampled, so ≤1.38.6 remains the publisher’s range rather than a claim that every historical release was independently executed. Commit 823843d1cd19182df79bc907c767f5bcecb39a0b added incomplete reserved-name hardening in 1.38.6, but it did not introduce the unsafe acceptance — 1.38.5 already lacked an equivalent protection. The exact introduction point was not established.

Upgrade to isomorphic-git 1.38.7 or later. More generally, code that writes attacker-controlled paths should perform platform-aware containment checks at the final filesystem boundary rather than rely on a growing list of forbidden spellings.

Regression coverage should include:

  1. .git::$INDEX_ALLOCATION and other .git stream declarations;
  2. .git case variants and trailing dot/space variants;
  3. git~1 and its stream variants;
  4. benign non-reserved colon names, which must keep working;
  5. clone and checkout assertions that the real gitdir is never modified by repository content.
2026-07-10
Windows/NTFS behaviour and exploit chain validated.
2026-07-11
isomorphic-git 1.38.7, GHSA-6fxm-h49m-4fg3 and CVE-2026-77355 published.
2026-08-26
Exact npm parser behaviour and cross-platform controls rechecked.
  1. GHSA-6fxm-h49m-4fg3 — isomorphic-git advisory and public PoC
  2. CVE-2026-77355 record
  3. Fixing commit — NTFS filename/stream split before reserved-name checks

Credit: Discovered and reported by Charles Vosburgh. Research was AI-assisted through source mapping, hypothesis generation, release comparison and evidence organization; final validation, disclosure coordination, severity calibration and publication review remained human.