Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
code-graph-rag-PoC — PoC — symlink following per lettura/scrittura arbitraria di file al di fuori della root del progetto in code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1). | Kitploit
Strumenti/GitHubGitHub/squeeze440/code-graph-rag-poc
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebPenetration TestingPaper e RicercaApprendimento e Formazione
GitHubsqueeze440/code-graph-rag-poc

code-graph-rag-PoC

PoC — symlink following per lettura/scrittura arbitraria di file al di fuori della root del progetto in code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1).

Vedi Repository
1020 giorni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

code-graph-rag: avviso di sicurezza

Stato CVE: richiesto, in attesa di assegnazione. Questa segnalazione è pubblicata come GHSA-85gg-2gfq-q95m. All'assegnazione del CVE questo repository viene rinominato CVE-YYYY-NNNNN-code-graph-rag-PoC e questo banner viene sostituito con il link al CVE.

RicercatoreDostxodjayev Abdullox (@squeeze440)
AvvisoGHSA-85gg-2gfq-q95m
CVSS 3.17.1 (Alto)
DebolezzaCWE-59, CWE-22

Sintesi

Un attaccante remoto/locale in grado di far includere un collegamento simbolico in un repository di codice sorgente che code-graph-rag analizza può causare l'accesso in lettura e — tramite structural_replace con dry_run=False — la sovrascrittura di file arbitrari al di fuori della root di progetto configurata da parte degli strumenti structural_search e structural_replace (supportati da AstGrepService, esposti sia come strumenti MCP sia come strumenti AI agentici), poiché il controllo di contenimento del percorso dello strumento (should_skip_path/_classify_file) viene eseguito lessicalmente sul percorso non risolto e non verifica mai Path.is_symlink() né chiama .resolve(), a differenza del decoratore validate_project_path (corretto) usato altrove nel progetto stesso.

Prodotto

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

Versione testata

Commit 90a3ed3cbdc7d3bb8036985b851cc7c9a3ba9c57 (versione pyproject 0.0.550) — main corrente al momento del test. Confermato che questo commit contiene già la correzione per l'avviso precedente (GHSA-vvr2-h2jp-838m: path traversal in read_file paginato) e il più recente gate di autenticazione bearer per HTTP-MCP (_validate_http_exposure in codebase_rag/mcp/server.py), quindi questo è un problema distinto, ancora aperto, al di sopra di tali correzioni.

CVSS v3.1 stimato

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

Metriche non ovvie:

  • AV:L — la falla è sfruttabile puramente attraverso l'uso principale locale/CLI/stdio-MCP dello strumento (analisi di un repository contenente un collegamento simbolico impiantato); non dipende dal trasporto HTTP MCP opzionale, ora protetto da token bearer, quindi il vettore di base è valutato sulla superficie locale sempre presente anziché presumere un deployment remoto.
  • UI:R — l'attaccante fornisce il repository malevolo (il collegamento simbolico), ma una parte separata (un utente, o un agente AI che agisce per suo conto) deve effettivamente eseguire structural_search/structural_replace su quel progetto perché la lettura/scrittura si attivi.
  • A:N — è stata dimostrata la sovrascrittura arbitraria del contenuto di un file; non è stata dimostrata alcuna catena di crash/DoS di sistema, quindi la Disponibilità è valutata conservativamente come None anziché presunta.

Dettagli

AstGrepService (codebase_rag/tools/ast_grep_service.py) supporta sia gli strumenti MCP/agentici structural_search sia structural_replace. Enumera i file candidati con os.walk() e filtra ogni percorso solo attraverso should_skip_path():

  • codebase_rag/tools/ast_grep_service.py:84-109 (_iter_source_files) — percorre self.project_root con os.walk(); ogni dirent non-directory restituito da os.walk (incluso un collegamento simbolico che punta ovunque sul disco) viene trattato come un file in ambito.
  • codebase_rag/tools/ast_grep_service.py:61-82 (_classify_file) — l'unico controllo di contenimento è should_skip_path(...) seguito da abs_path.relative_to(self.project_root) (riga 82); abs_path non viene mai risolto, quindi questo controllo è puramente lessicale/basato su stringhe.
  • codebase_rag/utils/path_utils.py:80-109 (should_skip_path) e codebase_rag/utils/path_utils.py:35-37 (cached_relative_path) — calcola rel_path = file_path.relative_to(repo_path) senza mai chiamare .resolve() o Path.is_symlink(). Nulla in questa funzione tratta un collegamento simbolico diversamente da un file reale.
  • Sink di lettura: codebase_rag/tools/ast_grep_service.py:143-144 (search) — source = self._read(abs_path) chiama path.read_text(), che Python segue attraverso il collegamento simbolico fino al suo target reale, indipendentemente da dove risieda quel target.
  • Sink di scrittura: codebase_rag/tools/ast_grep_service.py:187-208 (replace), in particolare la riga 208 — abs_path.write_text(new_source, ...) quando dry_run=False, seguendo nuovamente il collegamento simbolico e sovrascrivendo il contenuto del file target reale.

Ciò è incoerente con il modo in cui il resto del codebase gestisce esattamente la stessa classe di rischio. Gli strumenti di lettura/scrittura/modifica file (file_reader.py, file_writer.py, file_editor.py) sono tutti protetti da 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() segue i collegamenti simbolici prima che venga eseguito il controllo di contenimento, quindi quegli strumenti rifiutano correttamente un target fuori dalla root. Lo stesso absolute_path_within_project_root() di path_utils.py (codebase_rag/utils/path_utils.py:156-176) documenta esplicitamente lo stesso principio nella sua docstring: "Le chiamate a resolve() sono portanti: il contenimento è verificato lessicalmente, quindi un segmento .. non risolto o un collegamento simbolico sfuggirebbe alla root." — ma should_skip_path()/AstGrepService, usati da structural_search/structural_replace, non applicano mai quel pattern.

Raggiungibilità / esposizione dei due strumenti:

  • structural_search (codebase_rag/tools/structural_search.py:24-46) non porta alcun flag requires_approval — il modello di un client MCP può chiamarlo autonomamente senza conferma umana.
  • structural_replace (codebase_rag/tools/structural_editor.py:52-57) è contrassegnato con requires_approval=True, ma quel flag è applicato solo dal loop dell'agente di pydantic-ai stesso. Il percorso del server MCP lo aggira completamente: MCPToolsRegistry.structural_replace (codebase_rag/mcp/tools.py:586-596) chiama direttamente self._structural_editor_tool.function(...), e lo strumento MCP è registrato senza alcun concetto di approvazione in codebase_rag/mcp/tools.py:369-388 (ToolMetadata per MCPToolName.STRUCTURAL_REPLACE) — qualsiasi client MCP in grado di chiamare strumenti può invocare structural_replace con dry_run=False in un colpo solo.

Proof of Concept

Confermato dinamicamente contro il pacchetto installato (mgclient/pymgclient mockati esattamente come nel PoC dell'avviso precedente, poiché il client nativo Memgraph non è necessario per questo percorso di codice).

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)
Scarica lo strumento