{"id":"GHSA-96wc-2m84-2cj7","summary":"isomorphic-git: Circular symbolic references cause non-terminating resolution (DoS)","details":"### Summary\nA malicious server can advertise circular `symref=` capabilities (e.g. `a → b` and `b → a`). isomorphic-git writes them to disk as loose symrefs, and `GitRefManager.resolve()` follows them with no depth limit and no cycle detection, so any later operation that resolves one of them (`log`, `status`, `checkout`, `branch`, …) **loops forever** — a persistent denial of service from a single clone.\n\n### Details\n`src/managers/GitRefManager.js` — `resolve()` only enforces a depth limit when a `depth` argument is passed (`depth = undefined` by default), and has no visited-set:\n\n```js\nstatic async resolve({ fs, gitdir, ref, depth = undefined }) {\n  if (depth !== undefined) { depth--; if (depth === -1) return ref }\n  …\n}\n```\n\n`updateRemoteRefs` persists all server-supplied symrefs unconditionally. After clone the client has `refs/remotes/origin/a → ref: refs/remotes/origin/b` and `b → a` on disk; resolving either never terminates. Because the bad refs live on disk, the repo is effectively bricked for the application.\n\n#### Canonical git behavior (divergence)\ngit caps symref resolution at `SYMREF_MAXDEPTH = 5` (refs.c): `git rev-parse a` returns immediately with `warning: ignoring dangling symref` — no recursion, no hang.\n\n### PoC\n`https://github.com/spiceoverflow/av5-circular-symref` — open in a Codespace; clone writes the circular symrefs, then `git.log` on one never returns (the runner stops it after a 20s hang):\n\n```\n[AV-5] refs/remotes/origin/a contains: ref: refs/remotes/origin/b\n[AV-5] refs/remotes/origin/b contains: ref: refs/remotes/origin/a\n[run] *** DoS CONFIRMED: resolving a circular symref never terminates ***\n```\n\n### Impact\nA persistent denial of service via non-terminating symbolic-ref resolution (CWE-674 / CWE-835). After a single clone from a malicious (or MitM'd) server the circular refs are written to disk, so every later operation that resolves them (`log`, `status`, `checkout`, `branch`, …) hangs forever — the repository becomes effectively unusable for the application.\n\nImpacted: any application that clones from untrusted/compromised remotes with isomorphic-git.\n\n### Suggested fix\nAdd visited-set cycle detection (and/or a default maximum depth, as git does) in `GitRefManager.resolve()`; optionally validate server-supplied symref targets before persisting.","aliases":["CVE-2026-63475"],"modified":"2026-11-09T20:15:03.974348308Z","published":"2026-11-09T19:58:32Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-11-09T19:58:32Z","nvd_published_at":"2026-11-03T20:18:15Z","cwe_ids":["CWE-674","CWE-835"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/isomorphic-git/isomorphic-git/security/advisories/GHSA-96wc-2m84-2cj7"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-63475"},{"type":"WEB","url":"https://github.com/isomorphic-git/isomorphic-git/pull/2370"},{"type":"WEB","url":"https://github.com/isomorphic-git/isomorphic-git/commit/823843d1cd19182df79bc907c767f5bcecb39a0b"},{"type":"PACKAGE","url":"https://github.com/isomorphic-git/isomorphic-git"},{"type":"WEB","url":"https://github.com/isomorphic-git/isomorphic-git/releases/tag/v1.38.6"}],"affected":[{"package":{"name":"isomorphic-git","ecosystem":"npm","purl":"pkg:npm/isomorphic-git"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.38.6"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 1.38.5","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-96wc-2m84-2cj7/GHSA-96wc-2m84-2cj7.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L"}]}