CVE-2026-63312: NLTK Remote Code Execution Vulnerability
HIGHCVE-2026-63312 is a HIGH remote code execution vulnerability (CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')) affecting NLTK libraries in the PyPI ecosystem. The issue involves streambackedcorpusview bypasses pathsec.enforce - arbitrary local file read. Remediation is available by upgrading affected packages to version 3.10.0.
CVE-2026-63312 at a Glance
How to Fix CVE-2026-63312
To remediate this vulnerability, upgrade all affected NLTK dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
pip install nltk>=3.10.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
pip show nltk
How to Check if You Are Affected
To determine whether your Python environment is affected by CVE-2026-63312, inspect your installed packages using pip:
pip show nltk
Analyze the terminal output to locate any version of NLTK in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 3.10.0), your application is affected.
Note: The pip show nltk command checks currently installed packages in your active Python environment.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal'), where the product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory. In NLTK, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-63312 Affected NLTK Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
nltk
|
PyPI |
< 3.10.0
|
3.10.0
|
References
Frequently Asked Questions
What is CVE-2026-63312?
Which NLTK versions are affected?
What version fixes CVE-2026-63312?
Is nltk affected?
What CWE is associated with CVE-2026-63312?
How can I check PyPI dependencies for CVE-2026-63312?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-x5ph-mj9p-rfr8",
"modified" : "2026-09-08T15:27:33Z",
"published" : "2026-09-08T15:27:32Z",
"aliases" : [ "CVE-2026-63312" ],
"summary" : "NLTK: StreamBackedCorpusView Bypasses pathsec.ENFORCE - Arbitrary Local File Read",
"details" : "## Summary\nSetting `nltk.pathsec.ENFORCE = True` is documented to sandbox all file access to allowed NLTK data directories and raise `PermissionError` on unauthorized access. However, `StreamBackedCorpusView` opens files via `builtins.open()` directly, bypassing `pathsec.validate_path()` entirely. An attacker who can influence the `fileid` argument can read arbitrary local files regardless of the `ENFORCE` setting.\n\n## Details\n`nltk/pathsec.py:274` defines the enforcement point:\n```python\ndef open(file, mode=\"r\", **kwargs):\n validate_path(file, context=\"pathsec.open\")\n return builtins.open(file, mode=mode, **kwargs)\n```\n\n`StreamBackedCorpusView._open()` in `nltk/corpus/reader/util.py` bypasses this entirely for string paths:\n\n```python\n# line 171 — no validate_path() call\nself._eofpos = os.stat(self._fileid).st_size\n\n# line 208 — calls builtins.open directly\nself._stream = open(self._fileid, \"rb\")\n```\n\nAlso affected: `XMLCorpusView` and any corpus reader subclass that passes a raw string `fileid` to `StreamBackedCorpusView`.\n\n## PoC\n```python\n# poc_server.py — StreamBackedCorpusView pathsec.ENFORCE bypass\nfrom flask import Flask, request, jsonify\nimport nltk.pathsec as ps\nfrom nltk.corpus.reader.util import StreamBackedCorpusView, read_line_block\n\n# Strict mode enabled — expected to sandbox all file access\nps.ENFORCE = True\n\napp = Flask(__name__)\n\n@app.post(\"/read\")\ndef read_file():\n fname = request.json.get(\"file\")\n # fileid is user-controlled, passed directly to StreamBackedCorpusView\n # pathsec.ENFORCE = True is ignored — builtins.open() called internally\n view = StreamBackedCorpusView(fname, read_line_block, encoding=\"utf8\")\n return jsonify({\"file\": fname, \"content\": view[0]})\n\napp.run(host=\"0.0.0.0\", port=8000)\n```\nTrigger:\n```\ncurl -s -X POST http://localhost:8000/read \\\n -H \"Content-Type: application/json\" \\\n -d '{\"file\": \"/etc/passwd\"}'\n```\nConfirmed on latest stable NLTK. No privileges required.\n\n## Impact\n- **Type:** Arbitrary Local File Read / Security Control Bypass\n- **CWE:** CWE-22, CWE-284\n- **OWASP:** A01:2021 – Broken Access Control\n\nAffects web apps, REST APIs, and multi-tenant NLP pipelines where user input influences the `fileid` passed to NLTK corpus readers. Sensitive targets include `/etc/passwd`, `/proc/self/environ` (may contain `AWS_SECRET_ACCESS_KEY`, `DATABASE_URL`, etc.), and application config files.\n\nThe core issue is that operators who explicitly set `ENFORCE = True` to harden production deployments are left with a **false security guarantee**.\n\n**Suggested fix:** Replace `builtins.open()` and `os.stat()` in the string-path branch with `nltk.pathsec.open()` and `nltk.pathsec.validate_path()`.",
"severity" : [ {
"type" : "CVSS_V4",
"score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "PyPI",
"name" : "nltk"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "3.10.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 3.9.4"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/nltk/nltk/security/advisories/GHSA-x5ph-mj9p-rfr8"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-63312"
}, {
"type" : "WEB",
"url" : "https://github.com/nltk/nltk/pull/3588"
}, {
"type" : "WEB",
"url" : "https://github.com/nltk/nltk/commit/674ea75accdf08eca3782dee0a9c4ed7e0d0025b"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/nltk/nltk"
}, {
"type" : "WEB",
"url" : "https://github.com/nltk/nltk/releases/tag/v3.10.0"
}, {
"type" : "WEB",
"url" : "https://github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3730.yaml"
}, {
"type" : "WEB",
"url" : "https://www.vulncheck.com/advisories/nltk-streambackedcorpusview-bypasses-pathsec-enforce-arbitrary-file-read"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-22" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-09-08T15:27:32Z",
"nvd_published_at" : null
}
}