CVE-2026-87008: Out-of-Root Arbitrary File Read and Overwrite via Symlink Following in code-graph-rag

Vulnerability ID: CVE-2026-87008
CVSS Score: 7.1
Published: 2026-11-09

CVE-2026-87008 (GHSA-85gg-2gfq-q95m) is a high-severity symbolic link following and path traversal vulnerability in the code-graph-rag Python package prior to version 0.0.589. The flaw resides in the should_skip_path path validation routine inside codebase_rag/utils/path_utils.py, which performs directory containment checks using unresolved lexical paths rather than canonicalized filesystem paths. Consequently, symbolic links committed to an untrusted repository that point to targets outside the project root bypass boundary enforcement. Attackers who supply a crafted repository containing symbolic links can leverage the AstGrepService tool (structural_search and structural_replace) to read or overwrite arbitrary files on the host filesystem within the privileges of the running process.

TL;DR

Versions of code-graph-rag prior to 0.0.589 fail to resolve symbolic links before validating repository path containment in should_skip_path. By placing a symbolic link pointing to an external file within an analyzed repository, an attacker can read or overwrite arbitrary files on the host via structural_search and structural_replace, bypassing security boundary checks and Model Context Protocol (MCP) approval gates.

⚠️ Exploit Status: POC

Technical Details

  • CVE / GHSA ID: CVE-2026-87008 / GHSA-85gg-2gfq-q95m
  • Vulnerability Class: CWE-59 (Link Following) / CWE-22 (Path Traversal)
  • CVSS v3.1 Score: 7.1 High (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N)
  • Affected Component: should_skip_path() in codebase_rag/utils/path_utils.py & AstGrepService
  • Affected Versions: code-graph-rag < 0.0.589
  • Patched Version: code-graph-rag 0.0.589
  • Impact: Arbitrary out-of-root file read and file overwrite
  • Exploit / KEV Status: Public PoC Available / Not in CISA KEV (EPSS: 0.26%)

Affected Systems

  • vitali87/code-graph-rag (PyPI package: code-graph-rag)
  • code-graph-rag: < 0.0.589 (Fixed in: 0.0.589)

Code Analysis

Commit: 2648c95

fix: reject symlinks resolving outside the project root in should_skip_path

--- a/codebase_rag/utils/path_utils.py +++ b/codebase_rag/utils/path_utils.py @@ -120,6 +120,14 @@ def should_skip_path( _is_file = path.is_file() if is_file is None else is_file if _is_file and path.suffix in cs.IGNORE_SUFFIXES: return True + # Containment below is lexical, so a symlink whose target escapes the root + # would pass it and let a repo-scoped sweep read or overwrite outside files + # (GHSA-85gg-2gfq-q95m). Resolve first, mirroring validate_project_path + # (decorators.py) and absolute_path_within_project_root (this module). + try: + path.resolve().relative_to(repo_path.resolve()) + except ValueError: + return True rel_path = cached_relative_path(path, repo_path) rel_path_str = rel_path.as_posix() # a trailing slash marks the path as a directory for dir-only patterns. 

Exploit Details

  • GitHub: Public Proof-of-Concept repository demonstrating symlink escape via AstGrepService in code-graph-rag (GHSA-85gg-2gfq-q95m / CVE-2026-87008).

Mitigation Strategies

  • Upgrade code-graph-rag to version 0.0.589 or later to enforce canonical path resolution in should_skip_path.
  • Configure Git with core.symlinks=false when cloning untrusted repositories for static analysis or RAG indexing.
  • Execute code-graph-rag and associated MCP tool servers inside isolated containers without access to sensitive host directories.
  • Pre-scan untrusted repositories for symbolic links (find . -type l) and reject or sanitize them prior to indexing.

Remediation Steps:

  1. Identify all environments, developer workstations, and CI/CD pipelines running code-graph-rag versions prior to 0.0.589.
  2. Update the package via pip (pip install --upgrade "code-graph-rag>=0.0.589") or uv (uv add "code-graph-rag>=0.0.589").
  3. Verify the installed version using pip show code-graph-rag to confirm version 0.0.589 or newer is active.
  4. If running as an MCP server, restart the MCP host application or agent runner to ensure the updated Python module is loaded into memory.

References

Read the full report for CVE-2026-87008 on our website for more details including interactive diagrams and full exploit analysis.