{"id":"CVE-2026-63478","aliases":["EUVD-2026-116269","GHSA-cw2g-2vwq-88w6"],"status":"published","title":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","description":"isomorphic-git is a pure JavaScript implementation of Git for Node.js and browsers. Prior to 1.38.6, isomorphic-git's tree parser in src/models/GitTree.js accepts a standalone .. tree-entry name because it rejects only path separators. During clone or checkout from a malicious or man-in-the-middle-controlled non-GitHub remote, nested .. entries can escape the working-tree root and write files at attacker-selected parent paths on any host-backed fs provider. The arbitrary file write can overwrite startup or configuration files and lead to code execution. GitHub-hosted trees are not a direct source because GitHub rejects .. entries during repository integrity checks. This issue is fixed in version 1.38.6.","severity":{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00295,"percentile":0.22462,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-22"],"published":"2026-11-03T19:39:52.188Z","modified":"2026-11-09T20:30:04Z","fixes":[{"ecosystem":"npm","package":"isomorphic-git","fixed_in":["1.38.6"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"isomorphic-git","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"1.38.5"},{"fixed":"1.38.6"}]}]},{"source":"osv","ecosystem":"npm","package":"isomorphic-git","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.38.6"}]}]}],"products":[{"vendor":"isomorphic-git","product":"isomorphic-git"}],"references":[{"url":"https://github.com/isomorphic-git/isomorphic-git/security/advisories/GHSA-cw2g-2vwq-88w6","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/isomorphic-git/isomorphic-git/pull/2370","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/isomorphic-git/isomorphic-git/commit/823843d1cd19182df79bc907c767f5bcecb39a0b","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.6","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-63478","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-cw2g-2vwq-88w6"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63478.json","tags":["advisory"]},{"url":"https://github.com/isomorphic-git/isomorphic-git","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-63478","title":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","description":"isomorphic-git is a pure JavaScript implementation of Git for Node.js and browsers. Prior to 1.38.6, isomorphic-git's tree parser in src/models/GitTree.js accepts a standalone .. tree-entry name because it rejects only path separators. During clone or checkout from a malicious or man-in-the-middle-controlled non-GitHub remote, nested .. entries can escape the working-tree root and write files at attacker-selected parent paths on any host-backed fs provider. The arbitrary file write can overwrite startup or configuration files and lead to code execution. GitHub-hosted trees are not a direct source because GitHub rejects .. entries during repository integrity checks. This issue is fixed in version 1.38.6.","status":"published","published":"2026-11-03T19:39:52.188Z","modified":"2026-11-07T03:26:53.194Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-22"],"updated_at":"2026-11-07T04:32:31.343254Z"}],"euvd":[{"id":"EUVD-2026-116269","description":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","status":"published","published":"2026-11-09T20:13:52Z","modified":"2026-11-09T20:13:52Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"updated_at":"2026-11-09T21:18:10.039091Z"}],"ghsa":[{"id":"GHSA-cw2g-2vwq-88w6","title":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","description":"### Summary\nisomorphic-git's tree parser (`src/models/GitTree.js`) validates each entry name only against the path separators `/` and `\\`. It does not reject the standalone reserved name `..`, so a malicious repository can, on a single `clone`/`checkout`, **write files outside the working\ndirectory** (unbounded depth). Works on any host-backed `fs` provider.\n\n### Details\nThe guard is:\n\n```js\n// src/models/GitTree.js\nif (path.includes('\\\\') || path.includes('/')) {\n  throw new UnsafeFilepathError(path)\n}\n```\n\nThe standalone string `..` passes. isomorphic-git assembles the full path incrementally across tree levels, so nesting `..` trees yields `../escaped.txt`, `../../escaped.txt`, … with unbounded depth (each level is a separate tree object that passes the per-entry guard). On checkout `mkdir(workdir/..)` hits `EEXIST` (ignored) and the file is written above the working directory. Depth is chosen to reach the home dir, `/etc`, `/tmp`, etc.; overwriting a shell rc / config / startup file can escalate to code execution.\n\n#### Canonical git behavior (divergence)\ngit rejects this via `verify_path()`: `git read-tree` fails with `error: invalid path '../escaped.txt'` and `git fsck` flags `warning … hasDotdot: contains '..'`. (git's `verify_path` also rejects `.` and `.git`, the latter flagged by fsck as `hasDotgit` — see the fix note below.) GitHub runs fsck on push, so such a tree can't be hosted there; reach is limited to a self-hosted/Smart-HTTP remote or a MitM.\n\n\n### PoC\n`https://github.com/spiceoverflow/av2-dotdot-traversal` — open in a Codespace; a single `git.clone()` from the bundled server writes `escaped.txt` one directory above the clone target (`DEPTH=N` escapes N levels):\n\n```\n[AV-2] *** PATH TRAVERSAL CONFIRMED ***\n[AV-2] File written outside workdir: …/escaped.txt\n```\n\n### Impact\nA path-traversal arbitrary file write outside the working directory (CWE-22), triggered by a single clone/checkout; it can escalate to code execution by overwriting shell rc, config, or startup files.\n\nAny application or user that clones/checks out an untrusted (or compromised / MitM'd) repository with isomorphic-git on a host-backed filesystem (**Linux, macOS, or Windows** — no symlink or privilege required). Requires a non-GitHub remote (self-hosted / Smart-HTTP) or a MitM, since GitHub's fsck rejects trees containing `..`.\n\n### Suggested fix\nIn the tree parser, reject any entry name equal to `.` or `..`. For full `verify_path` parity it should **also** reject `.git` (case-insensitively, trailing dots/spaces stripped) and the NTFS 8.3 / HFS variants git blocks. Note: a literal `.git` entry is *not* independently exploitable via\n`clone`/`checkout` in current isomorphic-git — the checkout walk skips a `.git` tree entry (a sibling file is written but the `.git` entry is not), so rejecting `.git` is defense-in-depth / git parity rather than a separately demonstrated bug. Additionally, normalize and bounds-check the assembled full path against the working-tree root before any filesystem write.","status":"published","published":"2026-11-09T20:13:52Z","modified":"2026-11-09T20:13:52Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"cwes":["CWE-22"],"updated_at":"2026-11-09T20:19:39.584745Z"}],"nvd":[{"id":"CVE-2026-63478","description":"isomorphic-git is a pure JavaScript implementation of Git for Node.js and browsers. Prior to 1.38.6, isomorphic-git's tree parser in src/models/GitTree.js accepts a standalone .. tree-entry name because it rejects only path separators. During clone or checkout from a malicious or man-in-the-middle-controlled non-GitHub remote, nested .. entries can escape the working-tree root and write files at attacker-selected parent paths on any host-backed fs provider. The arbitrary file write can overwrite startup or configuration files and lead to code execution. GitHub-hosted trees are not a direct source because GitHub rejects .. entries during repository integrity checks. This issue is fixed in version 1.38.6.","status":"published","published":"2026-11-03T20:18:16.24Z","modified":"2026-11-07T04:17:33.56Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-22"],"updated_at":"2026-11-07T07:04:25.467195Z"}],"osv":[{"id":"CVE-2026-63478","title":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","description":"isomorphic-git is a pure JavaScript implementation of Git for Node.js and browsers. Prior to 1.38.6, isomorphic-git's tree parser in src/models/GitTree.js accepts a standalone .. tree-entry name because it rejects only path separators. During clone or checkout from a malicious or man-in-the-middle-controlled non-GitHub remote, nested .. entries can escape the working-tree root and write files at attacker-selected parent paths on any host-backed fs provider. The arbitrary file write can overwrite startup or configuration files and lead to code execution. GitHub-hosted trees are not a direct source because GitHub rejects .. entries during repository integrity checks. This issue is fixed in version 1.38.6.","status":"published","published":"2026-11-03T19:39:52.188Z","modified":"2026-11-08T02:30:46.038289052Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"cwes":["CWE-22"],"updated_at":"2026-11-11T11:06:49.938412Z"},{"id":"GHSA-cw2g-2vwq-88w6","title":"isomorphic-git: Path traversal via a \"..\" tree-entry name writes files outside the working directory on clone/checkout","description":"### Summary\nisomorphic-git's tree parser (`src/models/GitTree.js`) validates each entry name only against the path separators `/` and `\\`. It does not reject the standalone reserved name `..`, so a malicious repository can, on a single `clone`/`checkout`, **write files outside the working\ndirectory** (unbounded depth). Works on any host-backed `fs` provider.\n\n### Details\nThe guard is:\n\n```js\n// src/models/GitTree.js\nif (path.includes('\\\\') || path.includes('/')) {\n  throw new UnsafeFilepathError(path)\n}\n```\n\nThe standalone string `..` passes. isomorphic-git assembles the full path incrementally across tree levels, so nesting `..` trees yields `../escaped.txt`, `../../escaped.txt`, … with unbounded depth (each level is a separate tree object that passes the per-entry guard). On checkout `mkdir(workdir/..)` hits `EEXIST` (ignored) and the file is written above the working directory. Depth is chosen to reach the home dir, `/etc`, `/tmp`, etc.; overwriting a shell rc / config / startup file can escalate to code execution.\n\n#### Canonical git behavior (divergence)\ngit rejects this via `verify_path()`: `git read-tree` fails with `error: invalid path '../escaped.txt'` and `git fsck` flags `warning … hasDotdot: contains '..'`. (git's `verify_path` also rejects `.` and `.git`, the latter flagged by fsck as `hasDotgit` — see the fix note below.) GitHub runs fsck on push, so such a tree can't be hosted there; reach is limited to a self-hosted/Smart-HTTP remote or a MitM.\n\n\n### PoC\n`https://github.com/spiceoverflow/av2-dotdot-traversal` — open in a Codespace; a single `git.clone()` from the bundled server writes `escaped.txt` one directory above the clone target (`DEPTH=N` escapes N levels):\n\n```\n[AV-2] *** PATH TRAVERSAL CONFIRMED ***\n[AV-2] File written outside workdir: …/escaped.txt\n```\n\n### Impact\nA path-traversal arbitrary file write outside the working directory (CWE-22), triggered by a single clone/checkout; it can escalate to code execution by overwriting shell rc, config, or startup files.\n\nAny application or user that clones/checks out an untrusted (or compromised / MitM'd) repository with isomorphic-git on a host-backed filesystem (**Linux, macOS, or Windows** — no symlink or privilege required). Requires a non-GitHub remote (self-hosted / Smart-HTTP) or a MitM, since GitHub's fsck rejects trees containing `..`.\n\n### Suggested fix\nIn the tree parser, reject any entry name equal to `.` or `..`. For full `verify_path` parity it should **also** reject `.git` (case-insensitively, trailing dots/spaces stripped) and the NTFS 8.3 / HFS variants git blocks. Note: a literal `.git` entry is *not* independently exploitable via\n`clone`/`checkout` in current isomorphic-git — the checkout walk skips a `.git` tree entry (a sibling file is written but the `.git` entry is not), so rejecting `.git` is defense-in-depth / git parity rather than a separately demonstrated bug. Additionally, normalize and bounds-check the assembled full path against the working-tree root before any filesystem write.","status":"published","published":"2026-11-09T20:13:52Z","modified":"2026-11-09T20:30:04.108700086Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N","level":"medium"}],"cwes":["CWE-22"],"updated_at":"2026-11-09T20:39:59.362871Z"}]}}
