CVE-2026-80206: NLTK tgrep ReDoS: single request hangs Python process
GHSA-w3v8-gmh9-3wv7 HIGH PoC AVAILABLE CISA: TRACK*NLTK's tgrep module compiles user-supplied regular expressions and runs them against parse-tree node labels with no timeout, so a single crafted pattern like /((a+)+)b/ triggers catastrophic backtracking and pins a CPU core indefinitely. This matters because nltk has 2,997 downstream dependents and any service that exposes tgrep pattern search to external callers — linguistic annotation tools, corpus-query APIs, Jupyter-backed NLP demos — can be knocked out by one unauthenticated request, and in single-worker or thread-pooled Flask/FastAPI deployments that means every other user is denied service too. There's no CISA KEV listing, no public exploit or Nuclei template yet, and the EPSS raw score (0.00264) is low even though its percentile (top 82%) looks alarming, so this is not being mass-exploited today — it's a latent landmine, not a fire. No fixed release exists yet (still unpatched as of publication, target 3.10.3 per the advisory), so the immediate action is to stop passing untrusted input into `tgrep_positions()`/`tgrep_compile()`, wrap any exposed regex evaluation in a hard timeout or separate worker process, and track the nltk 3.10.3 release to patch as soon as it lands. Detection-wise, watch for sustained 100% single-core CPU on NLP worker processes correlated with tgrep/API request logs.
What is the risk?
High-severity, low-complexity, unauthenticated denial of service. No privileges or user interaction are required — a single crafted string is enough to hang the process indefinitely, and the vulnerable code path (`_tgrep_node_action` in tgrep.py) has no input validation or execution timeout. The saving grace is exposure: exploitation requires an application to expose tgrep pattern input to untrusted callers, which is a narrower surface than a general API vulnerability. No CVSS score is published, no CISA KEV entry, no known public PoC weaponization or scanner template, and EPSS's raw probability is low — but the attack is trivial to reproduce (the PoC is public in the advisory itself), so risk should be treated as real but currently opportunistic rather than actively exploited.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Jupyter Notebook | pip | <= 3.10.2 | 3.10.3 |
Do you use Jupyter Notebook? You're affected.
How severe is it?
What should I do?
1 step-
Upgrade to nltk 3.10.3 as soon as it is released (fix is in progress per the advisory; track https://github.com/nltk/nltk/releases). Until then: never pass untrusted/external input directly into tgrep pattern strings; if tgrep must accept user input, run the regex compilation/search in a separate process or thread with a hard wall-clock timeout (e.g.,
multiprocessingwith a timeout, or the third-partyregexmodule's timeout support) so a runaway match can be killed without taking down the whole worker. Apply request-level rate limiting on any endpoint that accepts tgrep patterns, and add monitoring/alerting for sustained single-core CPU saturation correlated with NLP worker processes as a detection signal for in-progress exploitation.
What does CISA's SSVC say?
Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-80206?
NLTK's tgrep module compiles user-supplied regular expressions and runs them against parse-tree node labels with no timeout, so a single crafted pattern like /((a+)+)b/ triggers catastrophic backtracking and pins a CPU core indefinitely. This matters because nltk has 2,997 downstream dependents and any service that exposes tgrep pattern search to external callers — linguistic annotation tools, corpus-query APIs, Jupyter-backed NLP demos — can be knocked out by one unauthenticated request, and in single-worker or thread-pooled Flask/FastAPI deployments that means every other user is denied service too. There's no CISA KEV listing, no public exploit or Nuclei template yet, and the EPSS raw score (0.00264) is low even though its percentile (top 82%) looks alarming, so this is not being mass-exploited today — it's a latent landmine, not a fire. No fixed release exists yet (still unpatched as of publication, target 3.10.3 per the advisory), so the immediate action is to stop passing untrusted input into `tgrep_positions()`/`tgrep_compile()`, wrap any exposed regex evaluation in a hard timeout or separate worker process, and track the nltk 3.10.3 release to patch as soon as it lands. Detection-wise, watch for sustained 100% single-core CPU on NLP worker processes correlated with tgrep/API request logs.
Is CVE-2026-80206 actively exploited?
Proof-of-concept exploit code is publicly available for CVE-2026-80206, increasing the risk of exploitation.
How to fix CVE-2026-80206?
Upgrade to nltk 3.10.3 as soon as it is released (fix is in progress per the advisory; track https://github.com/nltk/nltk/releases). Until then: never pass untrusted/external input directly into tgrep pattern strings; if tgrep must accept user input, run the regex compilation/search in a separate process or thread with a hard wall-clock timeout (e.g., `multiprocessing` with a timeout, or the third-party `regex` module's timeout support) so a runaway match can be killed without taking down the whole worker. Apply request-level rate limiting on any endpoint that accepts tgrep patterns, and add monitoring/alerting for sustained single-core CPU saturation correlated with NLP worker processes as a detection signal for in-progress exploitation.
What systems are affected by CVE-2026-80206?
This vulnerability affects the following AI/ML architecture patterns: NLP preprocessing pipelines, training data pipelines, multi-tenant inference APIs, notebook/interactive environments.
What is the CVSS score for CVE-2026-80206?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0029 Denial of AI Service AML.T0034.001 Resource-Intensive Queries AML.T0049 Exploit Public-Facing Application Compliance Controls Affected
What are the technical details?
Original Advisory
### Summary The NLTK `tgrep` module accepts user-supplied regular expressions and passes them to the Python `re` engine without a timeout or validation, enabling catastrophic backtracking (ReDoS). Applications that expose the `tgrep` API to external input are vulnerable to a single-request denial of service that blocks the Python process indefinitely. ### Affected Code `nltk/tgrep.py` — `_tgrep_node_action()` (around line 320) When a tgrep pattern contains a `/regex/` node, `_tgrep_node_action` compiles the embedded regex literal directly with no validation: ```python def _tgrep_node_action(_s, _l, tokens): ... elif tokens[0].startswith("/"): assert tokens[0].endswith("/") node_lit = tokens[0][1:-1] return ( lambda r: lambda n, m=None, l=None: r.search( _tgrep_node_literal_value(n) ) )(re.compile(node_lit)) # User regex compiled and executed with no timeout ``` The compiled regex is applied against every matching tree node label via `r.search(...)`. A caller reaching this path via `tgrep_positions()` or `tgrep_compile()` controls `node_lit` entirely. ### Proof of Concept ```python import nltk from nltk.tgrep import tgrep_positions # Root node label is 25 'a' characters. # tgrep /regex/ branch calls re.compile("((a+)+)b").search("aaa...a") # No 'b' is present — exponential backtracking occurs. tree = nltk.Tree.fromstring("(" + "a" * 25 + " (NP (DT the)))") tgrep_positions(r"/((a+)+)b/", [tree]) # Never returns ``` ### Working Poc The following script uses increasing values of n (the number of repeated as in the tree root label) to measure the execution time of tgrep_positions with the catastrophic regex /((a+)+)b/. On standard CPython with NLTK 3.10.2, the runtime grows exponentially, confirming the ReDoS vulnerability. For n ≥ 35, the function will hang indefinitely. ```python import nltk from nltk.tgrep import tgrep_positions import time def test_n(n): tree = nltk.Tree.fromstring("(" + "a" * n + " (NP (DT the)))") pattern = r"/((a+)+)b/" start = time.perf_counter() list(tgrep_positions(pattern, [tree])) return time.perf_counter() - start if __name__ == "__main__": # Adjust the range if needed – these values complete quickly n_values = [18, 20, 22, 24, 26, 28] print(f"Testing n = {n_values}\n") times = [] for n in n_values: t = test_n(n) times.append((n, t)) print(f"n={n:2d} done", flush=True) print("\n--- Increase factors (per step in n) ---") factors = [] for i in range(1, len(times)): prev_n, prev_t = times[i-1] curr_n, curr_t = times[i] factor = curr_t / prev_t factors.append((curr_n, factor)) print(f"n={curr_n:2d} : factor = {factor:.2f}x (vs n={prev_n})") avg = sum(f for _, f in factors) / len(factors) print(f"\nAverage factor: {avg:.2f}x") print("\n✅ Confirmed: exponential growth (catastrophic backtracking).") print(" Larger n (≥ 35) will hang indefinitely.") ``` When run, the output shows a clear exponential increase (factor > 3.0 per +2 in n), proving the vulnerability. ### Impact In environments like web APIs (Flask, FastAPI), Jupyter notebooks, or multi-tenant pipelines, an unauthenticated attacker can cause indefinite CPU saturation with a single crafted request, denying service to all other users of the process. ### Remediation This issue remains unfixed in versions `<= 3.10.2`. Maintainers are currently collaborating on a patch to wrap the regex execution in a timeout-guarded mechanism. ### Credit Tool: Kira by [Offgrid Security](https://www.offgridsec.com)
Exploitation Scenario
An application exposes a linguistic search feature — for example, a corpus-query API or an NLP annotation tool — that accepts tgrep pattern strings from end users and passes them to `tgrep_positions()`. An unauthenticated attacker submits a single query containing a `/regex/` node with a catastrophic pattern such as `/((a+)+)b/` matched against a tree with a long non-matching label. The Python process compiling and executing that regex enters exponential-time backtracking and never returns, pinning a CPU core at 100% indefinitely. Because the process is now blocked, all other requests sharing that worker (common in default single-threaded or small thread-pool deployments) are denied service until the process is manually killed and restarted.
Weaknesses (CWE)
CWE-1333 — Inefficient Regular Expression Complexity: The product uses a regular expression with a worst-case computational complexity that is inefficient and possibly exponential.
- [Architecture and Design] Use regular expressions that do not support backtracking, e.g. by removing nested quantifiers.
- [System Configuration] Set backtracking limits in the configuration of the regular expression implementation, such as PHP's pcre.backtrack_limit. Also consider limits on execution time for the process.
Source: MITRE CWE corpus.
References
- github.com/advisories/GHSA-w3v8-gmh9-3wv7
- github.com/nltk/nltk/commit/0072ea2fb8be22e038a36e887b7061bb6b9339d9
- github.com/nltk/nltk/releases/tag/v3.10.3
- github.com/nltk/nltk/security/advisories/GHSA-w3v8-gmh9-3wv7
- github.com/pypa/advisory-database/tree/main/vulns/nltk/PYSEC-2026-3751.yaml
- nvd.nist.gov/vuln/detail/CVE-2026-80206
- vulncheck.com/advisories/nltk-3.10.2-regular-expression-denial-of-service-via-tgrep
Timeline
Related Vulnerabilities
CVE-2026-72811 10.0 SiYuan: SQL injection enables cross-notebook DB access
Same package: notebook CVE-2026-69083 10.0 SiYuan: unauthenticated SQLi in full-text search endpoint
Same package: notebook CVE-2026-69084 10.0 SiYuan: SQL injection in search endpoint exposes notebooks
Same package: notebook CVE-2026-44727 9.0 jupyter-server: stored XSS yields kernel RCE
Same package: notebook CVE-2026-52798 8.9 Gogs: Stored XSS via .ipynb Markdown re-render bypass
Same package: notebook