Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
openlore-PoC — PoC — traversée de chemin via un champ de domaine dérivé d'un LLM non assaini dans OpenLore (GHSA-5j8x-q7q6-58j5, CVE-2026-87001, CVSS 4.7). | Kitploit
Outils/GitHubGitHub/squeeze440/openlore-poc
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionArticles et Recherche
GitHubsqueeze440/openlore-poc

openlore-PoC

PoC — traversée de chemin via un champ de domaine dérivé d'un LLM non assaini dans OpenLore (GHSA-5j8x-q7q6-58j5, CVE-2026-87001, CVSS 4.7).

Voir le dépôt
il y a 7 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Traversée de chemin dans le générateur de spécifications OpenLore via un champ domain non assaini dérivé du LLM

Statut CVE : demandé, en attente d'attribution. Cette découverte est publiée sous GHSA-5j8x-q7q6-58j5. À l'attribution de la CVE, ce dépôt est renommé CVE-YYYY-NNNNN-openlore-PoC et cette bannière est remplacée par le lien CVE.

ChercheurDostxodjayev Abdullox (@squeeze440)
AvisGHSA-5j8x-q7q6-58j5
CVSS 3.14.7 (Moyen)
FaiblesseCWE-22, CWE-73

Traversée de chemin dans le générateur de spécifications OpenLore via un champ domain non assaini dérivé du LLM

Résumé : Un attaquant qui contrôle le contenu d'un dépôt analysé par openlore generate peut amener le pipeline de génération de spécifications OpenSpec à écrire du Markdown influencé par l'attaquant vers un chemin arbitraire du système de fichiers en dehors du projet cible, car la valeur domain renvoyée par l'appel d'extraction LLM de l'étape 3 est utilisée telle quelle pour construire le chemin de sortie d'une spécification, sans assainissement de traversée ni vérification de confinement avant fs.writeFile.

Produit

OpenLore (clay-good/OpenLore), paquet npm openlore, pipeline de génération de spécifications (openlore generate / le générateur et l'écrivain au format OpenSpec). Il ne s'agit pas du chemin déterministe analyze/orient/garde-fou MCP — c'est le seul chemin de code du projet qui place intentionnellement un LLM dans la boucle de génération, conformément au README/spécification du projet lui-même (« un LLM n'est utilisé que là où la génération est inévitable (rédaction de spécifications), jamais dans le chemin de récupération ou de garde-fou »).

Version testée

Commit Git 1f2de00dfe75530efb256320c374dce36607ee70 (2026-07-31), version package.json 2.1.7.

CVSS v3.1 estimé

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

  • AV:L — le déclencheur est une invocation locale en ligne de commande (openlore generate) contre un répertoire sur disque, et non un service réseau.
  • AC:H — l'exploitation nécessite que l'opérateur exécute la commande generate adossée au LLM (et non le chemin de garde-fou par défaut) avec un fournisseur configuré, et nécessite que l'injection de prompt indirecte du dépôt analysé amène réellement le modèle à émettre une chaîne de traversée dans le champ domain — une condition que l'attaquant influence mais ne contrôle pas entièrement.
  • UI:R — l'opérateur doit choisir d'exécuter la génération de spécifications contre le dépôt malveillant.
  • I:H / C:N / A:N — le bug est une primitive d'écriture avec un contenu partiellement templaté par l'attaquant atterrissant à un chemin choisi par l'attaquant en dehors du projet ; il n'a pas été démontré qu'il lit des données confidentielles ou dégrade de manière fiable la disponibilité, ces métriques sont donc conservativement à N.

Détails

ExtractedService.domain (src/types/pipeline.ts:105) est renseigné directement depuis l'appel LLM de l'étape 3, auquel est fourni le contenu brut des fichiers du dépôt analysé et qui est invité à renvoyer un tableau JSON de services :

  • src/core/generator/stages/stage3-services.ts:45-52 construit le prompt à partir de fileChunks[i] (texte source littéral du dépôt analysé) et appelle pipeline.llm.completeJSON<ExtractedService[]>(..., STAGE3_SERVICE_SCHEMA).
  • src/core/generator/schemas.ts:100 — STAGE3_SERVICE_SCHEMA.items.properties.domain est { type: 'string' } : pas de pattern, pas d'enum, pas de liste d'autorisation. Toute chaîne renvoyée par le modèle est acceptée.
  • src/core/generator/openspec-format-generator.ts:161 — const domainName = service.domain || this.inferDomain(...) utilise cette chaîne telle quelle.
  • src/core/generator/openspec-format-generator.ts:563 — path: \openspec/specs/${domain.name.toLowerCase()}/spec.md`l'interpole directement dans le chemin de sortie déclaré de la spécification. À noter quenormalizeDomainName() (src/core/generator/openspec-compat.ts:655) existe dans le graphe de dépendances du même fichier et EST appliqué ailleurs (src/core/generator/openspec-writer.ts:167`, pour la comparaison des répertoires de domaines obsolètes) — mais il n'est jamais appelé ici, au seul endroit où la valeur devient réellement un chemin du système de fichiers.
  • src/core/generator/openspec-writer.ts:248 — const fullPath = join(this.rootPath, spec.path); utilise le simple node:path.join, qui résout lexicalement les segments ../, sans aucun appel au safeJoin() propre au projet (src/utils/path-confinement.ts) par lequel toutes les autres surfaces de chemin non fiable de ce codebase (les gestionnaires MCP, /api/skeleton et /api/spec-requirements de openlore view) doivent passer conformément à openspec/specs/mcp-security/spec.md.
  • src/core/generator/openspec-writer.ts:277 / :294 effectuent ensuite writeFile(fullPath, spec.content, 'utf-8'), et ensureDir() (openspec-writer.ts:497-499) exécute mkdir(dirname(filePath), { recursive: true }) sur le même chemin non confiné, créant tout répertoire intermédiaire manquant sur le chemin de sortie de la racine du projet.

Effet net : une valeur domain telle que ../../../../../../tmp/x survit intacte depuis la réponse JSON du LLM jusqu'à un véritable appel writeFile, atterrissant entièrement en dehors du projet analysé. C'est exactement le modèle de menace « le contenu du dépôt redirige une écriture en dehors de la racine du projet » que le propre openspec/specs/mcp-security/spec.md du projet définit explicitement et durcit sur les surfaces MCP/serve/view (safeJoin, confinement tenant compte des liens symboliques, porte de couverture des paramètres de chemin) — la surface générateur/écrivain n'a tout simplement pas de porte équivalente.

Preuve de concept

Aucun appel LLM réel n'a été effectué (la conformité du modèle à une instruction injectée est probabiliste et ne constitue pas la partie intéressante de ce bug) ; à la place, la PoC appelle les véritables OpenSpecFormatGenerator et OpenSpecWriter non modifiés d'OpenLore avec un PipelineResult dont l'unique champ ExtractedService.domain contient exactement la forme de chaîne que STAGE3_SERVICE_SCHEMA autorise aujourd'hui un LLM à renvoyer, et exactement ce qu'un commentaire dans un fichier source ordonnant « définir domain à ../../../.../tmp/x » pourrait susciter à l'étape 3 (qui transmet le contenu brut des fichiers au modèle).

Script : ~/engagements/openlore/source/poc-domain-traversal.ts (racine du dépôt du clone testé), exécuté contre un projet jetable à ~/engagements/openlore/evidence/victim-project :

root@kitploit:~
cd ~/engagements/openlore/source
npx tsx poc-domain-traversal.ts

Résultat : OpenSpecFormatGenerator.generateSpecs() (non modifié) émet une spécification de domaine avec path: "openspec/specs/../../../../../../../../../../../../../../../../../../../../tmp/openlore_traversal_proof/spec.md", et OpenSpecWriter.writeSpecs() (non modifié) l'écrit — atterrissant à /tmp/openlore_traversal_proof/spec.md, entièrement en dehors de la racine victim-project, tandis que victim-project/openspec/specs/ ne contient jamais que les deux répertoires légitimes overview/architecture.

Captures d'écran (authentiques captures Xvfb+fluxbox+xterm, scrot -w <window id>) :

  • ../evidence/poc-generator-write.png — l'exécution de la PoC : le spec.path brut du générateur contenant la traversée, la ligne de journal de l'écrivain Wrote openspec/specs/../../.../tmp/openlore_traversal_proof/spec.md, et la confirmation par le script lui-même que /tmp/openlore_traversal_proof/spec.md existe avec un contenu influencé par l'attaquant.
  • ../evidence/poc-outside-fs-proof.png — confirmation indépendante : ls de victim-project/openspec/specs/ ne montre que architecture/overview (aucune trace du domaine malveillant à l'intérieur du projet), tandis que ls -la /tmp/openlore_traversal_proof/ montre le spec.md évadé situé directement sous /tmp.

Impact

Un attaquant capable d'amener une cible à exécuter openlore generate (génération de spécifications adossée au LLM) contre un dépôt qu'il a rédigé — un scénario plausible pour un outil en ligne de commande dont le but explicite est d'être pointé vers des bases de code tierces/non fiables — peut écrire un fichier au contenu influencé par l'attaquant vers n'importe quel chemin accessible en écriture à l'utilisateur du système d'exploitation de l'opérateur, limité uniquement par le nombre de segments ../ nécessaires pour s'échapper et par les permissions du système de fichiers. L'écriture n'est pas confirmée comme directement exécutable, mais un chemin de projet suffisamment peu profond pourrait permettre à la traversée d'atteindre des emplacements exécutés ou chargés automatiquement par d'autres outils du même compte (fichiers rc du shell, répertoires cron de l'utilisateur, configuration d'éditeur/IDE), ce qui n'a pas été testé et n'est pas affirmé ici.

Faiblesses

  • CWE-22 : Limitation incorrecte d'un nom de chemin à un répertoire restreint (« Path Traversal »)
  • CWE-73 : Contrôle externe du nom de fichier ou du chemin
  • CWE-20 : Validation d'entrée incorrecte (cause racine — la sortie JSON du LLM est traitée comme si elle était générée en interne)

Remédiation

  1. Appliquer le normalizeDomainName() existant (ou une regex de liste d'autorisation équivalente, par ex. ^[a-z][a-z0-9-]{0,63}$) à domain.name / service.domain au moment où ils sont acceptés pour la première fois depuis la réponse du LLM (groupByDomain() dans openspec-format-generator.ts), et pas seulement au site ultérieur de comparaison des répertoires obsolètes.
  2. Faire passer le calcul de fullPath de OpenSpecWriter.writeSpec() par le safeJoin() propre au projet (src/utils/path-confinement.ts) au lieu du simple node:path.join, en accord avec le confinement déjà exigé de toutes les autres surfaces de chemin non fiable de ce codebase.
  3. Ajouter une contrainte pattern à STAGE3_SERVICE_SCHEMA.domain (et à tout autre champ de schéma utilisé ultérieurement pour construire un chemin du système de fichiers) afin que les fournisseurs qui appliquent les schémas de sortie structurée rejettent d'emblée les valeurs non conformes.
  4. Ajouter un test de non-régression — dans l'esprit de la « Path-Parameter Coverage Gate » MCP existante — vérifiant qu'un GeneratedSpec.path contenant .. ou se résolvant en dehors de rootPath est rejeté avant que OpenSpecWriter ne touche au système de fichiers.

Crédit

Dostxodjayev Abdullox

Canal de signalement

Le signalement privé de vulnérabilités GitHub est activé pour ce dépôt : https://github.com/clay-good/OpenLore/security/advisories/new (flux GHSA standard). Confirmé via gh api repos/clay-good/OpenLore/security-advisories renvoyant [] (aucun avis préalable) avant cet audit.

Télécharger l’outil