1. Executive summary
A path-sandbox bypass in the Python natural-language-toolkit library NLTK (version 3.10.2, commit 474af1f5a94b1b8d53fc2b6defec3a2ce7633b74) allows a caller who can control a corpus root path to read arbitrary files and SQLite databases outside the intended NLTK data sandbox, even with nltk.pathsec enforcement enabled. The flaw sits in CorpusReader.__init__() and is demonstrated through the public constructors LinThesaurusCorpusReader(root) and PanLexLiteCorpusReader(root), which use builtin open() and sqlite3.connect() directly on constructor-derived paths, bypassing the pathsec.open() guard. The advisory rates this 7.5 (High); no CISA-KEV exploitation state is recorded in the verified reference data for this item, and none should be assumed. Direct risk to EMEA financial services is limited to environments where untrusted input reaches an NLTK corpus-reader call site — typically ML/NLP pipelines, chatbot or document-processing services — where the impact is local file and database disclosure within the process's read permissions.
2. Regulatory framing
No specific DORA/NIS2 article is directly engaged by this item. The vulnerability is a library-level flaw with no confirmed exploitation, no incident, and no identified third-party provider relationship in the source material; generic "patching is required" mappings would fit every advisory and are not made here.
3. Technical analysis & attack chain
Vulnerability class: path sandbox bypass / external control of file path (CWE-classification not stated in the source; the advisory describes it as a sandbox bypass rather than assigning a CWE).
Affected component: nltk.corpus.reader constructors — CorpusReader.__init__ (nltk/corpus/reader/api.py, lines 73–80), LinThesaurusCorpusReader.__init__ (nltk/corpus/reader/lin.py, lines 37–43), PanLexLiteCorpusReader.__init__ (nltk/corpus/reader/panlex_lite.py, lines 45–46). Version tested: NLTK 3.10.2 on Python 3.13.14, PyPI package nltk.
Mechanism. NLTK is intended to enforce a data-root sandbox via nltk.pathsec, whose pathsec.open() refuses reads outside allowed roots when pathsec.ENFORCE = True. The bypass is structural: CorpusReader.__init__() converts a caller-supplied string root into a FileSystemPathPointer with no pathsec validation —
if zipfile:
root = ZipFilePathPointer(zipfile, zipentry)
else:
root = FileSystemPathPointer(root)
— and the concrete readers then perform I/O with builtin primitives on paths derived from that root, never passing through the sandboxed API:
with open(path) as lin_file:
...
self._c = sqlite3.connect(os.path.join(root, "db.sqlite")).cursor()
Because the constructor path never calls pathsec.open(), the guard is never reached. The measured unsafe effect is that outside-root file and database reads still occur with ENFORCE=True.
Attack chain (confirmed by the published PoC)
- Attacker controls, or can influence, the
rootargument passed to a corpus-reader constructor at some consumer call site (required privileges: none beyond the ability to supply a corpus root path). CorpusReader.__init__()wraps the raw string in aFileSystemPathPointerwithout validation.LinThesaurusCorpusReaderopens files under the root with builtinopen()— the PoC instrumentsbuiltins.openand confirms a read ofsimN.lspoutside the sandbox.PanLexLiteCorpusReadercallssqlite3.connect(os.path.join(root, "db.sqlite"))and successfully queries data (language_varieties()returns rows) from a database outside the sandbox.- Content read this way is returned to the caller — local information disclosure bounded by the process's filesystem read permissions.
The PoC (hy01_raw_path_poc.py) first proves the control: pathsec.open() on an outside path raises PermissionError (control:pathsec.open=blocked), then proves both readers succeed in the same process (lin:outside_root_open=success, panlex:language_varieties=success).
Scope and confidence caveats. This is a single-sourced advisory (GitHub Advisory Database entry GHSA-3gq4-3j92-5w49, mirrored as CVE-2026-79674); no second-party analysis, exploit-in-the-wild reporting, or vendor fix version is present in the material provided. The 7.5 (High) rating is the advisory's own severity reasoning — reliably triggerable via caller-controlled path input, crosses a trust boundary, no special privileges needed inside the process — and is used here as given. No CISA-KEV entry, EPSS score, or patch release is recorded in the verified reference data; do not treat this as under active exploitation. Note also that the bypass is a read primitive in the demonstrated cases (file read, SQLite read); the source does not demonstrate write or code-execution capability, and none should be inferred.
4. Mitigation & containment
No vendor fix version is identified in the source material; the remediation guidance below is the advisory's own (validate raw string roots before constructing readers; route all corpus-root/path handling through pathsec or a validated PathPointer; remove direct builtin open() and direct sqlite3.connect(os.path.join(...)) use on constructor-derived paths). Until a patched release is confirmed, treat the library as unpatched.
P1 — within 24h
- Inventory for
nltk(PyPI) in build manifests, requirements files, container images and ML/NLP service codebases; confirm whether version 3.10.2 or the affected commit range is in use. - Identify every call site that passes an externally influenceable string to a corpus-reader constructor (
LinThesaurusCorpusReader(root),PanLexLiteCorpusReader(root), and by extension anyCorpusReadersubclass taking a raw string root). Grep forCorpusReader(,LinThesaurusCorpusReader(,PanLexLiteCorpusReader(across service code.
P2 — within 72h
- At each such call site, validate the root before construction: resolve the path, confirm it is a subdirectory of an explicit allow-listed data root, and reject absolute paths,
..traversal and symlinks escaping the allow-list. Do not rely onpathsec.ENFORCE = True— the PoC demonstrates it does not cover this path. - Where the call site cannot be modified immediately, deny-list the vulnerable readers at the import boundary (e.g. block
nltk.corpus.reader.lin/nltk.corpus.reader.panlex_liteimports in the service) or run the NLP workload in a container whose filesystem exposes only the intended corpus directory, so an outside-root read has nothing sensitive to reach. - Run the published PoC (
hy01_raw_path_poc.py) against your pinned NLTK build to confirm whether your version is affected before and after any change.
P3 — within 7 days
- Monitor the GHSA/NLTK release channel for a patched version and pin to it on release; until then pin to a known-good usage pattern (validated roots only) in CI policy.
- Add a CI check that fails builds introducing unvalidated string roots into corpus-reader constructors.
5. Indicators of compromise
No indicators of compromise available in the source material. This is a vulnerability advisory with a proof-of-concept; no malicious artefacts, network indicators or attacker infrastructure are described.
6. Detection
The source provides no threat artefacts (no malicious files, command lines, mutexes, or attacker-controlled strings) — the PoC is a defensive demonstration, not malware. The vulnerability leaves no distinctive log signature beyond ordinary file-read behaviour by the NLTK process. Practical detection is therefore behavioural and environment-specific: audit logging on the service account running NLTK workloads, alerting on file opens outside the configured corpus data directory (e.g. via auditd openat syscalls or container runtime file-access monitoring), and on sqlite3.connect calls resolving to database files outside the corpus root. No YARA or Sigma rule can be authored from this material without fabricating strings.
7. Sources
- GitHub Advisory Database — "NLTK: Corpus Reader Sandbox Bypass" (GHSA-3gq4-3j92-5w49 / CVE-2026-79674) — https://github.com/advisories/GHSA-3gq4-3j92-5w49 — published 2026-09-08
8. Adverse Trace position
This is a genuine, PoC-confirmed sandbox bypass in a widely used Python NLP library, rated 7.5 (High) by the issuing advisory — a rating we carry as given, not re-assessed. Practical severity for EMEA financial services is conditional: the flaw requires an attacker to control a corpus root path at a call site, so the exposed population is ML/NLP pipelines and document- or chat-processing services that pass user-influenced paths to NLTK readers, and the demonstrated impact is local file/SQLite disclosure within process permissions, not the ransomware or extortion activity seen in higher-priority items. The advisory is single-sourced with no vendor patch, no CISA-KEV entry and no observed exploitation recorded in the verified reference data; we therefore treat it as a hardening and inventory priority rather than an incident. We will monitor for a patched NLTK release, independent confirmation, and any KEV/EPSS movement, and will reissue if exploitation or a fix version is confirmed.
Published via PulseTrace — Adverse Trace threat intelligence.