Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
code-graph-rag-PoC — PoC — seguimiento de enlaces simbólicos para lectura/escritura arbitraria de archivos fuera de la raíz del proyecto en code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1). | Kitploit
Herramientas/GitHubGitHub/squeeze440/code-graph-rag-poc
Análisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de PenetraciónPapers e InvestigaciónAprendizaje y Educación
GitHubsqueeze440/code-graph-rag-poc

code-graph-rag-PoC

PoC — seguimiento de enlaces simbólicos para lectura/escritura arbitraria de archivos fuera de la raíz del proyecto en code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1).

Ver Repositorio
10hace 19 díasAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

code-graph-rag: aviso de seguridad

Estado del CVE: solicitado, pendiente de asignación. Este hallazgo se publica como GHSA-85gg-2gfq-q95m. Al asignarse el CVE, este repositorio se renombra CVE-YYYY-NNNNN-code-graph-rag-PoC y este banner se reemplaza con el enlace del CVE.

InvestigadorDostxodjayev Abdullox (@squeeze440)
AvisoGHSA-85gg-2gfq-q95m
CVSS 3.17.1 (Alto)
DebilidadCWE-59, CWE-22

Resumen

Un atacante remoto/local que logre incluir un enlace simbólico en un repositorio de código fuente que code-graph-rag analiza puede provocar que las herramientas structural_search y structural_replace (respaldadas por AstGrepService, expuestas tanto como herramientas MCP como herramientas de IA agéntica) lean y — mediante structural_replace con dry_run=False — sobrescriban archivos arbitrarios fuera de la raíz del proyecto configurada, porque la comprobación de contención de rutas de la herramienta (should_skip_path/_classify_file) se realiza léxicamente sobre la ruta sin resolver y nunca comprueba Path.is_symlink() ni llama a .resolve(), a diferencia del propio decorador (correcto) validate_project_path del proyecto, usado en otros lugares.

Producto

vitali87/code-graph-rag (PyPI: code-graph-rag, CLI: cgr)

Versión probada

Commit 90a3ed3cbdc7d3bb8036985b851cc7c9a3ba9c57 (versión de pyproject 0.0.550) — main actual en el momento de la prueba. Se confirmó que este commit ya contiene la corrección del aviso anterior (GHSA-vvr2-h2jp-838m: path traversal en read_file paginado) y la puerta de autenticación bearer del HTTP-MCP más reciente (_validate_http_exposure en codebase_rag/mcp/server.py), por lo que este es un problema distinto y aún abierto sobre esas correcciones.

CVSS v3.1 estimado

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N — 7.0 (Alto)

Métricas no obvias:

  • AV:L — el fallo es explotable puramente a través del uso local/CLI/stdio-MCP principal de la herramienta (analizar un repositorio que contiene un enlace simbólico plantado); no depende del transporte HTTP MCP opcional, ahora protegido con token bearer, por lo que el vector base se puntúa sobre la superficie local siempre presente en lugar de asumir un despliegue remoto.
  • UI:R — el atacante proporciona el repositorio malicioso (el enlace simbólico), pero una parte separada (un usuario, o un agente de IA actuando en su nombre) debe ejecutar realmente structural_search/structural_replace contra ese proyecto para que se dispare la lectura/escritura.
  • A:N — se demostró la sobrescritura arbitraria del contenido de un archivo; no se demostró ninguna cadena de caída/DoS del sistema, por lo que la Disponibilidad se puntúa de forma conservadora como None en lugar de asumirse.

Detalles

AstGrepService (codebase_rag/tools/ast_grep_service.py) respalda tanto las herramientas MCP/agénticas structural_search como structural_replace. Enumera los archivos candidatos con os.walk() y filtra cada ruta únicamente a través de should_skip_path():

  • codebase_rag/tools/ast_grep_service.py:84-109 (_iter_source_files) — recorre self.project_root con os.walk(); cada entrada de directorio no-directorio devuelta por os.walk (incluido un enlace simbólico que apunte a cualquier lugar del disco) se trata como un archivo dentro del alcance.
  • codebase_rag/tools/ast_grep_service.py:61-82 (_classify_file) — la única comprobación de contención es should_skip_path(...) seguida de abs_path.relative_to(self.project_root) (línea 82); abs_path nunca se resuelve, por lo que esta comprobación es puramente léxica/basada en cadenas.
  • codebase_rag/utils/path_utils.py:80-109 (should_skip_path) y codebase_rag/utils/path_utils.py:35-37 (cached_relative_path) — calcula rel_path = file_path.relative_to(repo_path) sin llamar nunca a .resolve() ni a Path.is_symlink(). Nada en esta función trata un enlace simbólico de forma diferente a un archivo real.
  • Sumidero de lectura: codebase_rag/tools/ast_grep_service.py:143-144 (search) — source = self._read(abs_path) llama a path.read_text(), que Python sigue a través del enlace simbólico hasta su objetivo real, sin importar dónde resida ese objetivo.
  • Sumidero de escritura: codebase_rag/tools/ast_grep_service.py:187-208 (replace), concretamente la línea 208 — abs_path.write_text(new_source, ...) cuando dry_run=False, siguiendo de nuevo el enlace simbólico y sobrescribiendo el contenido del archivo objetivo real.

Esto es inconsistente con cómo el resto del código base maneja exactamente la misma clase de riesgo. Las herramientas de lectura/escritura/edición de archivos (file_reader.py, file_writer.py, file_editor.py) están todas protegidas por validate_project_path (codebase_rag/decorators.py:73-75):

full_path = (self.project_root / file_path_str).resolve()
project_root = self.project_root.resolve()
full_path.relative_to(project_root)

.resolve() sigue los enlaces simbólicos antes de que se ejecute la comprobación de contención, por lo que esas herramientas rechazan correctamente un objetivo fuera de la raíz. El propio absolute_path_within_project_root() de path_utils.py (codebase_rag/utils/path_utils.py:156-176) documenta el mismo principio explícitamente en su docstring: "Las llamadas a resolve() son fundamentales: la contención se comprueba léxicamente, por lo que un segmento .. sin resolver o un enlace simbólico escaparía de la raíz." — pero should_skip_path()/AstGrepService, usados por structural_search/structural_replace, nunca aplican ese patrón.

Alcance / exposición de las dos herramientas:

  • structural_search (codebase_rag/tools/structural_search.py:24-46) no lleva ningún indicador requires_approval en absoluto — el modelo de un cliente MCP puede llamarla de forma autónoma sin confirmación humana.
  • structural_replace (codebase_rag/tools/structural_editor.py:52-57) está marcada con requires_approval=True, pero ese indicador solo lo aplica el propio bucle de agente de pydantic-ai. La ruta del servidor MCP lo omite por completo: MCPToolsRegistry.structural_replace (codebase_rag/mcp/tools.py:586-596) llama directamente a self._structural_editor_tool.function(...), y la herramienta MCP se registra sin ningún concepto de aprobación en codebase_rag/mcp/tools.py:369-388 (ToolMetadata para MCPToolName.STRUCTURAL_REPLACE) — cualquier cliente MCP que pueda llamar a herramientas puede invocar structural_replace con dry_run=False de una sola vez.

Prueba de concepto

Confirmado dinámicamente contra el paquete instalado (mgclient/pymgclient simulados exactamente como en la PoC del aviso anterior, ya que el cliente nativo de Memgraph no es necesario para esta ruta de código).

mkdir -p /tmp/poc_symlink/safe-project-root
cat > /tmp/poc_symlink/outside-secret.py << 'EOF'
API_TOKEN = "sk-live-EXAMPLE-NOT-A-REAL-SECRET-1234567890"
def get_token():
    return API_TOKEN
EOF
ln -s /tmp/poc_symlink/outside-secret.py /tmp/poc_symlink/safe-project-root/linked_module.py
# poc.py
import sys
from pathlib import Path
from unittest.mock import MagicMock
sys.modules["mgclient"] = MagicMock()
sys.modules["pymgclient"] = MagicMock()
from codebase_rag.tools.ast_grep_service import AstGrepService

SAFE_ROOT = "/tmp/poc_symlink/safe-project-root"
svc = AstGrepService(project_root=SAFE_ROOT)

matches = svc.search(pattern="API_TOKEN", language="python")
# -> match in reported file='linked_module.py' text='API_TOKEN'  (read escape)
Descargar herramienta