~/f4n6 $ grep -r "NLTK: Corpus Reader Sandbox Bypass" ./investigations/ --include="*.md"

NLTK: Corpus Reader Sandbox Bypass

Jeff Davies 10 Sep 2026 5 min read

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)

  1. Attacker controls, or can influence, the root argument passed to a corpus-reader constructor at some consumer call site (required privileges: none beyond the ability to supply a corpus root path).
  2. CorpusReader.__init__() wraps the raw string in a FileSystemPathPointer without validation.
  3. LinThesaurusCorpusReader opens files under the root with builtin open() — the PoC instruments builtins.open and confirms a read of simN.lsp outside the sandbox.
  4. PanLexLiteCorpusReader calls sqlite3.connect(os.path.join(root, "db.sqlite")) and successfully queries data (language_varieties() returns rows) from a database outside the sandbox.
  5. 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 any CorpusReader subclass taking a raw string root). Grep for CorpusReader(, 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 on pathsec.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_lite imports 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.


Read the original source →

Published via PulseTrace — Adverse Trace threat intelligence.

Post this to LinkedIn
Formatting is converted automatically — headings, bullets, a link back & hashtags. Paste straight in.
J
Jeff Davies