Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
code-graph-rag-PoC — PoC — seguir link simbólico para leitura/escrita arbitrária de ficheiros fora da raiz do projeto em code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1). | Kitploit
Ferramentas/GitHubGitHub/squeeze440/code-graph-rag-poc
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoPapers e PesquisaAprendizado e Educação
GitHubsqueeze440/code-graph-rag-poc

code-graph-rag-PoC

PoC — seguir link simbólico para leitura/escrita arbitrária de ficheiros fora da raiz do projeto em code-graph-rag (GHSA-85gg-2gfq-q95m, CVE-2026-87008, CVSS 7.1).

Ver Repositório
10há 19 diasAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

code-graph-rag: aviso de segurança

Status da CVE: solicitada, aguardando atribuição. Esta descoberta é publicada como GHSA-85gg-2gfq-q95m. Após a atribuição da CVE, este repositório é renomeado CVE-YYYY-NNNNN-code-graph-rag-PoC e este banner é substituído pelo link da CVE.

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

Resumo

Um atacante remoto/local que consiga incluir um link simbólico em um repositório de código-fonte que o code-graph-rag analisa pode fazer com que as ferramentas structural_search e structural_replace (suportadas pelo AstGrepService, expostas tanto como ferramentas MCP quanto como ferramentas de IA agêntica) leiam e — via structural_replace com dry_run=False — sobrescrevam arquivos arbitrários fora da raiz do projeto configurada, porque a verificação de contenção de caminho da ferramenta (should_skip_path/_classify_file) é realizada lexicalmente sobre o caminho não resolvido e nunca verifica Path.is_symlink() nem chama .resolve(), ao contrário do próprio decorador (correto) validate_project_path do projeto, usado em outros lugares.

Produto

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

Versão Testada

Commit 90a3ed3cbdc7d3bb8036985b851cc7c9a3ba9c57 (versão do pyproject 0.0.550) — main atual no momento do teste. Confirmado que este commit já contém a correção para o aviso anterior (GHSA-vvr2-h2jp-838m: path traversal no read_file paginado) e o gate mais recente de autenticação bearer do HTTP-MCP (_validate_http_exposure em codebase_rag/mcp/server.py), portanto este é um problema distinto e ainda em aberto sobre essas correções.

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 não óbvias:

  • AV:L — a falha é explorável puramente através do uso central local/CLI/stdio-MCP da ferramenta (analisando um repositório contendo um link simbólico plantado); não depende do transporte HTTP MCP opcional, agora protegido por bearer token, portanto o vetor base é pontuado na superfície local sempre presente, em vez de assumir uma implantação remota.
  • UI:R — o atacante fornece o repositório malicioso (o link simbólico), mas uma parte separada (um usuário, ou um agente de IA agindo em seu nome) deve realmente executar structural_search/structural_replace contra esse projeto para que a leitura/escrita seja acionada.
  • A:N — a sobrescrita arbitrária do conteúdo de um arquivo foi demonstrada; nenhuma cadeia de crash/DoS do sistema foi demonstrada, portanto a Disponibilidade é pontuada conservadoramente como Nenhuma em vez de assumida.

Detalhes

O AstGrepService (codebase_rag/tools/ast_grep_service.py) suporta tanto as ferramentas MCP/agênticas structural_search quanto structural_replace. Ele enumera arquivos candidatos com os.walk() e filtra cada caminho apenas através de should_skip_path():

  • codebase_rag/tools/ast_grep_service.py:84-109 (_iter_source_files) — percorre self.project_root com os.walk(); cada dirent que não é diretório retornado por os.walk (incluindo um link simbólico apontando para qualquer lugar do disco) é tratado como um arquivo dentro do escopo.
  • codebase_rag/tools/ast_grep_service.py:61-82 (_classify_file) — a única verificação de contenção é should_skip_path(...) seguida de abs_path.relative_to(self.project_root) (linha 82); abs_path nunca é resolvido, portanto esta verificação é puramente lexical/baseada em string.
  • codebase_rag/utils/path_utils.py:80-109 (should_skip_path) e codebase_rag/utils/path_utils.py:35-37 (cached_relative_path) — calcula rel_path = file_path.relative_to(repo_path) sem nunca chamar .resolve() ou Path.is_symlink(). Nada nesta função trata um link simbólico de forma diferente de um arquivo real.
  • Sink de leitura: codebase_rag/tools/ast_grep_service.py:143-144 (search) — source = self._read(abs_path) chama path.read_text(), que o Python segue através do link simbólico até seu alvo real, não importa onde esse alvo esteja.
  • Sink de escrita: codebase_rag/tools/ast_grep_service.py:187-208 (replace), especificamente a linha 208 — abs_path.write_text(new_source, ...) quando dry_run=False, novamente seguindo o link simbólico e sobrescrevendo o conteúdo do arquivo alvo real.

Isso é inconsistente com a forma como o restante da base de código lida com exatamente a mesma classe de risco. As ferramentas de leitura/escrita/edição de arquivos (file_reader.py, file_writer.py, file_editor.py) são 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() segue links simbólicos antes que a verificação de contenção seja executada, portanto essas ferramentas rejeitam corretamente um alvo fora da raiz. O próprio absolute_path_within_project_root() do path_utils.py (codebase_rag/utils/path_utils.py:156-176) documenta o mesmo princípio explicitamente em sua docstring: "As chamadas resolve() são essenciais: a contenção é verificada lexicalmente, portanto um segmento .. não resolvido ou um link simbólico escaparia da raiz." — mas should_skip_path()/AstGrepService, usados por structural_search/structural_replace, nunca aplicam esse padrão.

Alcance / exposição das duas ferramentas:

  • structural_search (codebase_rag/tools/structural_search.py:24-46) não possui nenhuma flag requires_approval — o modelo de um cliente MCP pode chamá-la autonomamente sem confirmação humana.
  • structural_replace (codebase_rag/tools/structural_editor.py:52-57) está marcada com requires_approval=True, mas essa flag só é aplicada pelo próprio loop de agente do pydantic-ai. O caminho do servidor MCP a ignora completamente: MCPToolsRegistry.structural_replace (codebase_rag/mcp/tools.py:586-596) chama self._structural_editor_tool.function(...) diretamente, e a ferramenta MCP é registrada sem nenhum conceito de aprovação em codebase_rag/mcp/tools.py:369-388 (ToolMetadata para MCPToolName.STRUCTURAL_REPLACE) — qualquer cliente MCP que possa chamar ferramentas pode invocar structural_replace com dry_run=False em um único disparo.

Prova de Conceito

Confirmado dinamicamente contra o pacote instalado (mgclient/pymgclient mockados exatamente como no PoC do aviso anterior, já que o cliente nativo do Memgraph não é necessário para este caminho 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)

changes = svc.replace(pattern="API_TOKEN", rewrite="PWNED_BY_STRUCTURAL_REPLACE",
                       language="python", dry_run=False)
print(Path("/tmp/poc_symlink/outside-secret.py").read_text())

Saída real da execução (/tmp/poc_venv, pacote instalado via pip install --no-deps -e . a partir do commit testado):

Baixar ferramenta