> ## Content Index
> Fetch the complete content index at: https://f4n6.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# NLTK: Corpus Reader Sandbox Bypass
- URL: https://f4n6.co.uk/security-feed/nltk-corpus-reader-sandbox-bypass/
- Published: 2026-09-10T15:42:36.000Z
- Updated: 2026-09-10T15:42:36.000Z
- Author: Jeff Davies
- Tags: #security-feed

## 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 —

```python
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:

```python
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 →](https://github.com/advisories/GHSA-3gq4-3j92-5w49?ref=f4n6.co.uk)

*Published via PulseTrace — Adverse Trace threat intelligence.*