Like leaving a treasure-map bookmark inside a library book that leads the librarian to read your diary instead
CVE-2026-62384 affects NLTK versions before 3.10.2. The flaw lives in FramenetCorpusReader — specifically the frame_by_name(), _lu_file(), and doc() methods. An attacker who can write to the corpus subdirectory on disk can plant a symlink whose name contains no path separators. When the reader processes that filename, it passes the lexical path-validation check (nltk.pathsec) but the OS resolves the symlink to a file outside the corpus root, letting the attacker read arbitrary XML-parseable files. The affected scope is NLTK < 3.10.2, fixed in 3.10.2.
The vendor labels this HIGH 7.5 with CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N. That vector is misleading. The attack requires the ability to create symlinks inside the corpus directory on the local filesystem — that is fundamentally a local-access prerequisite, not a network one. The only plausible remote vector is tricking a user into installing a malicious corpus package that embeds symlinks, which is a supply-chain social-engineering step the CVSS doesn't price in. The confidentiality impact is further limited to files that are valid XML. No integrity or availability impact exists. The vendor severity overstates the real-world risk.
4 steps from start to impact.
Gain write access to NLTK corpus directory
~/nltk_data/corpora/framenet_v17/ or a custom path). This can be achieved via local shell access, or by convincing the victim to install a trojanized NLTK corpus package that embeds symlinks. On multi-user research servers, a co-tenant with write access to a shared corpus directory could also reach this step.- Local or shared filesystem write access to the NLTK corpus directory
- Knowledge of the corpus directory path on the target
- Requires prior compromise of the host or social engineering the user into installing a malicious corpus
- On single-user workstations (the majority of NLTK installs), this requires the attacker to already be on the box — at which point they can likely read files directly
- Shared corpus directories are uncommon in production; most deployments use per-user
~/nltk_data
Plant symlink in corpus subdirectory
frame/) whose filename contains no path separators (e.g., evil.xml -> /etc/passwd). The name must be crafted so that frame_by_name() or doc() will attempt to open it. Because pathsec validates the path lexically without resolving symlinks, the check passes.- Symlink creation capability (on Windows this requires SeCreateSymbolicLinkPrivilege or Developer Mode)
- Target file must be XML-parseable for data to be extracted meaningfully
- On Windows, unprivileged symlink creation is disabled by default — Developer Mode or admin rights required
- The target file must parse as valid XML, limiting what can actually be exfiltrated (e.g.,
/etc/shadowis not XML) - Tar/zip extraction in recent Python versions and NLTK >= 3.9.4 may strip symlinks from corpus archives
Trigger corpus read via application
frame_by_name(), _lu_file(), or doc() on the FramenetCorpusReader with input that resolves to the planted symlink. In an interactive research session this might happen naturally; in a production NLP service, it would require the service to expose FrameNet lookup to user-controlled input, which is rare.- Application uses FramenetCorpusReader (a niche corpus reader for the FrameNet lexical database)
- Application calls one of the three vulnerable methods with attacker-influenced input
- FrameNet is an academic linguistic resource — few production services expose FrameNet queries to untrusted users
- Most NLTK production use cases involve tokenization, POS tagging, or sentiment — not FrameNet corpus reading
- If the application hardcodes corpus queries, the attacker cannot direct which file is read
Exfiltrate file contents
cat the file), or the application must return the parsed data to the network. The exfiltrated content is filtered through an XML parser, so non-XML files produce errors rather than data.- A return channel for the parsed data (screen output, API response, logs)
- Target file must be well-formed XML
- If the attacker already has shell access to read corpus dirs, they can read most target files directly without this CVE
- XML-only parsing dramatically limits useful exfiltration targets
- Error output from malformed XML might leak partial data but is unreliable
The supporting signals.
| In-the-Wild Exploitation | No known exploitation. Not listed on CISA KEV. No campaigns or threat-actor use reported as of 2026-08-24. |
|---|---|
| Proof of Concept | No public PoC identified. The SecureWithUmer/CVE-2026-PoCs repo does not appear to include this CVE. Exploitation is conceptually simple (create a symlink) but weaponization against a remote target is non-trivial. |
| EPSS Score | 0.00657 (≈0.66%) — low probability of exploitation in the next 30 days. Bottom quartile. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-08-24. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N — 7.5 HIGH. noisgate assessment: AV:N is inaccurate; realistic vector is closer to AV:L given the symlink-creation prerequisite. |
| Affected Versions | NLTK < 3.10.2. All prior versions with FramenetCorpusReader and pathsec sandbox are vulnerable. |
| Fixed Version | NLTK 3.10.2 (PyPI) |
| Exposure Data | NLTK has ~50M+ monthly PyPI downloads, but the vast majority are dev/research workstations and CI environments, not internet-facing services. FramenetCorpusReader is a small fraction of NLTK usage. No Shodan/Censys/GreyNoise signatures relevant — this is a library, not a listening service. |
| Disclosure Date | 2026-08-22 |
| Reporter | Not publicly attributed. Part of a batch of NLTK pathsec bypass findings (CVE-2026-62383, CVE-2026-62384, CVE-2026-62385, CVE-2026-65915). |
noisgate verdict.
The single most decisive factor driving this downgrade is the mislabeled attack vector: exploiting this CVE requires local filesystem write access to plant symlinks in the corpus directory, yet the vendor CVSS claims AV:N/PR:N. Once corrected to AV:L, the base score drops below 6.0, and the niche scope of FramenetCorpusReader plus XML-only read constraint compress real-world impact further.
Why this verdict
- AV:N is wrong — this is a local-access bug. The attacker must create symlinks on the target filesystem inside the corpus directory. The only remote path is via a trojanized corpus package, which is a separate supply-chain social-engineering attack not captured in the CVSS.
- FramenetCorpusReader is niche. FrameNet is an academic linguistics dataset. The fraction of NLTK's 50M+ monthly installs that actively use
FramenetCorpusReaderin production services exposed to untrusted input is vanishingly small — likely well under 1%. - XML-only read limits blast radius. The exfiltrated file must parse as valid XML. High-value targets like
/etc/shadow, database credentials files, and most config files are not XML, severely limiting what an attacker can steal. - Role multiplier: NLTK is a library, not infrastructure. It does not occupy any high-value role (not an IdP, hypervisor, backup agent, network edge, CI/CD server, or security agent). In its most common deployment — data-science workstations and Jupyter notebooks — a local attacker who can write to
~/nltk_dataalready has equivalent or greater read access. In rare ML-pipeline server deployments, the FramenetCorpusReader is unlikely to be in the code path. No high-value-role floor applies. - No exploitation signals. Zero KEV listing, no known PoCs, EPSS at 0.66%. Two days post-disclosure with no attacker interest.
Why not higher?
Upgrading to HIGH would require either a genuine unauthenticated remote attack path or exploitation in a high-value-role component. Neither applies: the network vector is a CVSS labeling error (symlink creation is local), FramenetCorpusReader is an academic corpus reader not found in identity/infrastructure roles, and the read-only XML-constrained impact does not reach code execution or domain compromise.
Why not lower?
Despite heavy friction, this is a real sandbox bypass in a widely-installed library (50M+ downloads/month). A trojanized corpus package distributed through a compromised NLTK data mirror *could* weaponize this without direct host access. The confidentiality impact on XML-formatted files (which includes many application configs, Maven POMs, Spring configs, and .csproj files) is non-trivial. Dropping to LOW would undercount the supply-chain angle.
What to do — in priority order.
- Upgrade NLTK to 3.10.2 — The definitive fix. Run
pip install --upgrade nltk>=3.10.2across all environments. Since this is assessed as MEDIUM, the noisgate remediation SLA gives you 365 days, but given the trivial upgrade path, aim to roll it into your next dependency-update cycle. - Restrict write access to NLTK corpus directories — Ensure
~/nltk_dataand any shared corpus paths are owned by the application user with mode 0755 (not world-writable). On shared research servers, use per-user corpus roots. This eliminates the symlink-planting prerequisite entirely. - Pin corpus data sources — If you use
nltk.download()in CI/CD or automated pipelines, pin to the official NLTK data server and verify checksums. Do not accept corpus packages from untrusted mirrors or user uploads. - Enable file-integrity monitoring on corpus directories — Deploy FIM (OSSEC, Wazuh, auditd) rules to alert on symlink creation inside NLTK corpus directories. This provides detection of exploitation attempts.
- WAF / network IDS — this is not a network-exploitable vulnerability; no HTTP payload or network signature exists to detect or block.
- Sandboxing NLTK with
pathsec.ENFORCE=True— that is exactly the sandbox being bypassed by this CVE; it does not help until you upgrade to 3.10.2. - Python virtual environments — venvs isolate packages but do not restrict filesystem symlink creation within the corpus directory.
Crowdsourced verification payload.
Run this script on any host where NLTK is installed. It checks the installed NLTK version against the fix. No special privileges required. Invoke with: python check_cve_2026_62384.py
#!/usr/bin/env python3
"""Check for CVE-2026-62384: NLTK FramenetCorpusReader symlink sandbox bypass.
Affected: NLTK < 3.10.2
Fixed: NLTK >= 3.10.2
"""
import sys
try:
import nltk
except ImportError:
print("UNKNOWN - NLTK is not installed on this system.")
sys.exit(2)
try:
from packaging.version import Version
except ImportError:
# fallback to distutils (deprecated but available in older Pythons)
from distutils.version import LooseVersion as Version
installed = nltk.__version__
fixed = "3.10.2"
try:
if Version(installed) < Version(fixed):
print(f"VULNERABLE - NLTK {installed} is installed (fix: >= {fixed}). CVE-2026-62384 applies.")
sys.exit(1)
else:
print(f"PATCHED - NLTK {installed} is installed (fix: >= {fixed}). CVE-2026-62384 does not apply.")
sys.exit(0)
except Exception as e:
print(f"UNKNOWN - Could not compare versions: {e}")
sys.exit(2)If you remember one thing.
pip install --upgrade nltk>=3.10.2) during your next scheduled dependency refresh. If you run shared multi-tenant research or ML-pipeline servers with writable corpus directories, tighten directory permissions this week as a compensating control. There is no active exploitation, no KEV listing, and EPSS is under 1% — this is a backlog item, not a fire drill.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.