CVE-2026-80206: NLTK tgrep ReDoS: single request hangs Python process

GHSA-w3v8-gmh9-3wv7 HIGH PoC AVAILABLE CISA: TRACK*
Published September 8, 2026
CISO Take

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.

Sources: NVD GitHub Advisory EPSS OpenSSF ATLAS

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?

Entry point
Attacker submits a tgrep pattern containing a malicious /regex/ node to an application that exposes tree-pattern search to external input.
AML.T0049
Exploitation
_tgrep_node_action compiles the attacker-controlled regex with no validation and runs it against every matching tree node label, triggering catastrophic backtracking.
AML.T0034.001
Impact
The Python process is pinned at 100% CPU indefinitely, denying service to every user sharing that worker until it is manually killed.
AML.T0029

What systems are affected?

Package Ecosystem Vulnerable Range Patched
Jupyter Notebook pip <= 3.10.2 3.10.3
13.3K OpenSSF 5.7 3.0K dependents Pushed 9d ago 83% patched ~108d to patch Full package profile →

Do you use Jupyter Notebook? You're affected.

How severe is it?

CVSS 3.1
N/A
EPSS
0.3%
chance of exploitation in 30 days
Higher than 19% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Trivial
Exploitation Confidence
medium
CISA SSVC: Public PoC
Public PoC indexed (trickest/cve)
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What should I do?

1 step
  1. 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 does CISA's SSVC say?

Decision Track*
Exploitation poc
Automatable No
Technical Impact partial

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:

EU AI Act
Article 15 - Accuracy, robustness and cybersecurity
NIST AI RMF
MEASURE 2.7 - AI system resilience and security testing
OWASP LLM Top 10
LLM10:2025 - Unbounded Consumption

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

NLP preprocessing pipelinestraining data pipelinesmulti-tenant inference APIsnotebook/interactive environments

MITRE ATLAS Techniques

AML.T0029 Denial of AI Service
AML.T0034.001 Resource-Intensive Queries
AML.T0049 Exploit Public-Facing Application

Compliance Controls Affected

EU AI Act: Article 15
NIST AI RMF: MEASURE 2.7
OWASP LLM Top 10: LLM10:2025

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.

Timeline

Published
September 8, 2026
Last Modified
September 8, 2026
First Seen
September 9, 2026

Related Vulnerabilities