CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-126300

CVE-2026-126300: Algorithmic Complexity Denial of Service in NLTK TreebankWordTokenizer.span_tokenize

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 13, 2026·10 min read·1 visit

Executive Summary (TL;DR)

An O(n^2) algorithmic complexity flaw in NLTK's span_tokenize method (versions >= 3.2.5, < 3.10.4) occurs due to repeated list.pop(0) calls during quote restoration. Processing inputs with large numbers of double quotes causes severe CPU exhaustion, which is resolved in NLTK 3.10.4 by using collections.deque.popleft().

CVE-2026-126300 (GHSA-ffr9-mgrr-wcvr) is an inefficient algorithmic complexity vulnerability (CWE-407) in the Natural Language Toolkit (NLTK) Python library affecting versions 3.2.5 prior to 3.10.4. The flaw resides in the quote-restoration routine of TreebankWordTokenizer.span_tokenize and NLTKWordTokenizer.span_tokenize, where repeated calls to list.pop(0) over matched quote tokens introduce quadratic O(n^2) time complexity. An unauthenticated remote attacker who supplies input containing long sequences of double-quote characters can exhaust CPU resources and degrade service availability.

Vulnerability Overview

The Natural Language Toolkit (NLTK) is a widely deployed Python library used for symbolic and statistical natural language processing (NLP). Among its core text preprocessing primitives are TreebankWordTokenizer (defined in nltk/tokenize/treebank.py) and its destructive counterpart NLTKWordTokenizer (defined in nltk/tokenize/destructive.py). These classes provide both standard word tokenization and span tokenization (span_tokenize), which calculates the exact start and end character offsets (start, end) for every token in a given source string.

Span tokenization is frequently exposed on the attack surface of web applications, document ingestion pipelines, named entity recognition (NER) services, and search indexing backends. Whenever an application must correlate extracted tokens back to their exact positions in raw user-submitted text—such as for syntax highlighting, annotation alignment, or clinical text extraction—it invokes span_tokenize on untrusted input.

In NLTK versions 3.2.5 through 3.10.3, both TreebankWordTokenizer.span_tokenize and NLTKWordTokenizer.span_tokenize contain an algorithmic complexity flaw classified under CWE-407 (Inefficient Algorithmic Complexity) and CWE-400 (Uncontrolled Resource Consumption). When restoring converted Penn Treebank directional quotes back to their original literal representations, the routine uses a standard Python list as a first-in, first-out (FIFO) queue by calling list.pop(0) inside a list comprehension.

Because removing the leading element from a contiguous array in CPython requires shifting all remaining elements in memory, executing list.pop(0) across $n$ quote tokens degrades execution from linear $O(n)$ time to quadratic $O(n^2)$ time. An unauthenticated attacker capable of submitting text payloads containing thousands of quote characters can occupy a CPU core for several seconds or minutes per request, leading to worker thread starvation and denial of service.

Root Cause Analysis

The root cause of CVE-2026-126300 lies in how span_tokenize reconciles Penn Treebank tokenization conventions with raw string offset mapping. During initial tokenization (self.tokenize(text)), the Treebank tokenizer converts standard ASCII double quotes (") into directional opening quotes ( ``) and closing quotes (''). Because these converted tokens no longer match the exact characters in the source text, direct substring searching to calculate character spans would fail unless the original quote characters are restored prior to alignment.

To perform this restoration, span_tokenize inspects the input string to check whether " or '' is present. If found, it executes a regular expression scan using redos.finditer(r"``|'{2}|\"", text) and collects every matched quote substring into a standard Python list named matched. Subsequently, it iterates through raw_tokens—the output of self.tokenize(text)—and replaces each quote token ('"', "``", or "''") with the next original character sequence by invoking matched.pop(0).

In the CPython runtime, a list object (PyListObject) is implemented as an over-allocated, contiguous C array of PyObject* pointers (ob_item). While appending or popping from the end of a Python list operates in amortized $O(1)$ constant time, removing the element at index 0 via list.pop(0) (internally handled by list_ass_slice or list_pop_impl) requires shifting every remaining pointer from index 1 through $k-1$ one position to the left using memmove. Consequently, a single call to matched.pop(0) on a list of length $k$ incurs $O(k)$ memory movement overhead.

When an input string consists of $n$ double-quote characters, matched is initialized with $n$ elements and raw_tokens contains $n$ corresponding quote tokens. The list comprehension invokes matched.pop(0) exactly $n$ times as the list shrinks from $n$ down to $1$. The total number of pointer shift operations follows the arithmetic series:

$$\sum_{k=1}^{n} (k - 1) = \frac{n(n - 1)}{2} = O(n^2)$$

> [!NOTE] > Existing safeguards in NLTK do not intercept this condition. First, unlike SyllableTokenizer or LegalitySyllableTokenizer, TreebankWordTokenizer.span_tokenize enforces no MAX_TOKEN_LEN input boundary check. Second, although NLTK wraps regular expression operations in nltk/redos.py to enforce regex execution timeouts and prevent catastrophic backtracking, the quadratic delay in CVE-2026-126300 occurs inside a pure-Python list comprehension after redos.finditer has already completed in linear time.

Code Analysis

The vulnerable logic is duplicated across two files in the NLTK repository: nltk/tokenize/treebank.py (within TreebankWordTokenizer.span_tokenize) and nltk/tokenize/destructive.py (within NLTKWordTokenizer.span_tokenize). Both implementations share the same quote-matching and restoration block.

In the unpatched code prior to version 3.10.4, matched is constructed via a list comprehension and mutated via matched.pop(0):

# Vulnerable implementation in nltk/tokenize/treebank.py (lines 202-214)
if ('"' in text) or ("''" in text):
    # Find double quotes and converted quotes
    # VULNERABILITY: matched is constructed as a contiguous CPython list
    matched = [m.group() for m in redos.finditer(r"``|'{2}|\"", text)]
 
    # Replace converted quotes back to double quotes
    # VULNERABILITY: matched.pop(0) shifts all remaining list elements left in O(k) time.
    # Executed across all quote tokens in raw_tokens, total complexity is O(n^2).
    tokens = [
        matched.pop(0) if tok in ['"', "``", "''"] else tok
        for tok in raw_tokens
    ]
else:
    tokens = raw_tokens

Upstream commit e20c40e26ec9306de885703f6e53250695f1f49b (merged via Pull Request #3895) remediates the vulnerability in both nltk/tokenize/treebank.py and nltk/tokenize/destructive.py by importing collections.deque and replacing the list comprehension with a deque generator initialization:

--- a/nltk/tokenize/treebank.py
+++ b/nltk/tokenize/treebank.py
@@ -19,6 +19,7 @@
 
 import re
 import warnings
+from collections import deque
 from collections.abc import Iterator
 from typing import List, Tuple
 
@@ -202,11 +203,13 @@ def span_tokenize(self, text: str) -> Iterator[tuple[int, int]]:
         # treated as starting quotes).
         if ('"' in text) or ("''" in text):
             # Find double quotes and converted quotes
-            matched = [m.group() for m in redos.finditer(r"``|'{2}|\"", text)]
+            # A deque keeps popleft() O(1); a list.pop(0) here is O(n) per token,
+            # so text with many quotes made span_tokenize O(n**2) (CWE-407).
+            matched = deque(m.group() for m in redos.finditer(r"``|'{2}|\"", text))
 
             # Replace converted quotes back to double quotes
             tokens = [
-                matched.pop(0) if tok in ['"', "``", "''"] else tok
+                matched.popleft() if tok in ['"', "``", "''"] else tok
                 for tok in raw_tokens
             ]
         else:

In CPython, collections.deque is implemented as a doubly linked list of fixed-size pointer blocks (64 elements per block). Calling matched.popleft() simply increments the left index cursor of the head block (and frees the block when exhausted) without shifting any subsequent pointers in memory. This guarantees strict $O(1)$ time complexity per token restoration and restores the overall span_tokenize method to $O(n)$ linear scaling.

Fix Completeness Assessment: The patch completely eliminates the quadratic bottleneck in the quote restoration path for both TreebankWordTokenizer and NLTKWordTokenizer. Furthermore, downstream call align_tokens(tokens, text) advances a single monotonic character pointer point across text, which operates in $O(n)$ time. No residual quadratic behavior remains in the span_tokenize execution path.

Exploitation

Exploiting CVE-2026-126300 requires no authentication or complex payload formatting beyond reaching an application endpoint that passes user-controlled text into TreebankWordTokenizer().span_tokenize() or NLTKWordTokenizer().span_tokenize(). Note that span_tokenize returns a Python generator (Iterator[tuple[int, int]]), but the vulnerable matched.pop(0) loop executes eagerly before the first yield from align_tokens(tokens, text) statement is reached, meaning the CPU stall occurs immediately upon the first iteration (such as calling list() or iterating in a for loop).

An attacker crafts a string consisting solely of repeated double-quote characters ('"' * n). Because every byte in the payload is tokenized as a quote token and matched by r"``|'{2}|\"", the payload achieves maximum token density: a 256 KB string produces 256,000 elements in matched and triggers 256,000 sequential list.pop(0) calls, resulting in approximately $3.27 \times 10^{10}$ pointer movements.

The following proof-of-concept script demonstrates the quadratic scaling behavior by measuring execution duration across doubling payload sizes and comparing it against a non-quote control payload of identical character and token count:

import time
from nltk.tokenize import TreebankWordTokenizer
 
tok = TreebankWordTokenizer()
 
print("[*] Testing TreebankWordTokenizer.span_tokenize quadratic complexity:")
for n in (32000, 64000, 128000, 256000):
    payload = '"' * n
    start = time.perf_counter()
    list(tok.span_tokenize(payload))
    duration = time.perf_counter() - start
    print(f"  [+] quote-run length={n:<7}: {duration:.3f} seconds")
 
# Control run with equal token count (128,000 tokens, 256,000 chars)
# that bypasses the quote-restoration branch
control = "a " * 128000
start = time.perf_counter()
list(tok.span_tokenize(control))
duration = time.perf_counter() - start
print(f"  [*] control non-quote length=256000: {duration:.3f} seconds")

Empirical benchmark measurements confirm the $O(n^2)$ time growth where doubling the input length increases execution time by nearly a factor of 4:

  • '"' * 32000 (32 KB): 0.23 seconds
  • '"' * 64000 (64 KB): 0.52 seconds (~2.26x increase)
  • '"' * 128000 (128 KB): 1.76 seconds (~3.38x increase)
  • '"' * 256000 (256 KB): 6.57 seconds (~3.73x increase)
  • "a " * 128000 (256 KB Control): 0.16 seconds (~41x faster than the quote payload)

At 512,000 characters (~512 KB), a single invocation blocks the Python interpreter for approximately 26 seconds. Payloads exceeding 1 MB block a CPU core for several minutes while holding the Global Interpreter Lock (GIL) during each C-level memmove operation.

Impact Assessment

The primary security impact of CVE-2026-126300 is Application-Layer Denial of Service (DoS) via CPU exhaustion. The vulnerability has no direct impact on confidentiality or integrity, as the memory shifts stay strictly within the allocated bounds of the PyListObject pointer array.

In synchronous Python web frameworks (such as Flask, Django, or FastAPI running synchronous worker endpoints under Gunicorn or uWSGI), each worker process typically handles a single request at a time, or shares a single Python interpreter across multiple OS threads constrained by the CPython Global Interpreter Lock (GIL). When an attacker submits a few concurrent HTTP requests containing 256 KB to 1 MB of repeated quote characters, all available worker processes become saturated in the matched.pop(0) loop.

The National Vulnerability Database (NVD) and GitHub Advisory Database score this vulnerability at CVSS v3.1 5.3 (MEDIUM) (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L), while the assigning CNA (VulnCheck) assigns a CVSS v4.0 score of 6.9 (MEDIUM) (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N). Both vectors reflect that the flaw is network-exploitable without privileges, user interaction, or special attack requirements (AV:N/AC:L/PR:N/UI:N), with a Low availability impact (A:L / VA:L) because the service recovers automatically once the long-running tokenization calls finish.

According to threat intelligence metrics, CVE-2026-126300 is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. It holds a FIRST EPSS score of 0.00509 (0.51%), placing it at the 44.01st percentile of indexed vulnerabilities. While public proof-of-concept benchmark code is available in the security advisory, no automated mass-exploitation campaigns have been observed.

Remediation

The definitive remediation for CVE-2026-126300 is to upgrade the nltk package to version 3.10.4 or later. In version 3.10.4, the collections.deque.popleft() replacement reduces the execution time for a 128,000-character quote payload from 1.76 seconds down to under 0.20 seconds, restoring linear $O(n)$ performance across all input compositions.

Administrators and developers should update their environment dependencies using pip or their respective package manager:

pip install --upgrade "nltk>=3.10.4"

For environments where an immediate dependency upgrade cannot be deployed, security engineers should apply defense-in-depth controls at the application boundary:

  1. Input Size Clamping: Enforce strict request body and field length limits at the API gateway, reverse proxy (e.g., NGINX client_max_body_size), or application validation layer (such as Pydantic max_length constraints) before passing text to NLP tokenizers.
  2. Quote Density Filtering: Pre-validate or sanitize untrusted strings to reject or collapse pathological runs of consecutive quote characters (for example, rejecting inputs matching the pattern "{50,} or ('{2}|``){50,}) prior to invoking span_tokenize.
  3. Process Isolation and Task Timeouts: Offload heavy NLP preprocessing to isolated background worker processes (such as Celery or RQ with multiprocessing pools) configured with hard execution timeouts (time_limit), ensuring that runaway tokenization tasks are terminated without starving main web server threads.

Official Patches

NLTK Project (GitHub Pull Request #3895)Official pull request fixing O(n^2) quote restoration in span_tokenize.
NLTK Project (GitHub Commit)Upstream patch commit replacing list.pop(0) with deque.popleft().
NLTK Project (Release v3.10.4)NLTK 3.10.4 release containing the security fix.

Fix Analysis (1)

Technical Appendix

CVSS Score
5.3/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
EPSS Probability
0.51%
Top 56% most exploited

Affected Systems

Natural Language Toolkit (NLTK) Python Package (pkg:pypi/nltk)TreebankWordTokenizer (nltk.tokenize.treebank)NLTKWordTokenizer (nltk.tokenize.destructive)

Affected Versions Detail

Product
Affected Versions
Fixed Version
nltk
NLTK Project
>= 3.2.5, < 3.10.43.10.4
AttributeDetail
Vulnerability TypeCWE-407: Inefficient Algorithmic Complexity (O(n^2) DoS)
Affected ComponentTreebankWordTokenizer.span_tokenize / NLTKWordTokenizer.span_tokenize
Attack VectorNetwork (Unauthenticated untrusted text input)
CVSS v3.1 / v4.05.3 MEDIUM (v3.1) / 6.9 MEDIUM (v4.0)
EPSS Score0.51% (44.01st Percentile)
ImpactCPU Exhaustion / Application Denial of Service
Exploit StatusPublic Proof-of-Concept (PoC) Available
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.004Application or System Exploitation
Impact
CWE-407
Inefficient Algorithmic Complexity

An algorithm in a product has an inefficient worst-case computational complexity that is detrimental to system performance and can be triggered by an attacker to cause resource exhaustion.

Known Exploits & Detection

GitHubPublic benchmark proof-of-concept script demonstrating quadratic CPU time scaling in TreebankWordTokenizer.span_tokenize using repeated double-quote payloads.

Vulnerability Timeline

Vulnerability reported by security researcher (@manus-pi) and fix committed upstream in commit e20c40e26ec9306de885703f6e53250695f1f49b (PR #3895).
2026-09-16
Benchmark verification confirmed linear O(n) execution on patched branches.
2026-09-28
NLTK version 3.10.4 released on PyPI containing the fix.
2026-11-13
CVE-2026-126300 (GHSA-ffr9-mgrr-wcvr) published by VulnCheck CNA and indexed by NVD and GitHub Advisory Database.
2026-11-13

References & Sources

  • [1]GitHub Security Advisory: GHSA-ffr9-mgrr-wcvr
  • [2]VulnCheck Advisory: NLTK CPU Exhaustion via TreebankWordTokenizer.span_tokenize
  • [3]NLTK Pull Request #3895
  • [4]Official Fix Commit e20c40e26ec9306de885703f6e53250695f1f49b
  • [5]NLTK Upstream Release v3.10.4
  • [6]National Vulnerability Database (NVD): CVE-2026-126300
  • [7]CVE.org Official Record: CVE-2026-126300

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•GHSA-GPWC-27CW-RH9R
5.3

CVE-2026-126301: Quadratic CPU Exhaustion in NLTK LegalitySyllableTokenizer

The Natural Language Toolkit (NLTK) versions 3.6 through 3.10.3 contain an algorithmic complexity vulnerability in the LegalitySyllableTokenizer.tokenize method. When processing tokens composed of continuous runs of vowels, an unguarded string reversal and set membership lookup loop executes in quadratic time relative to the input token length. Remote attackers capable of submitting arbitrary text to applications utilizing this tokenizer can trigger sustained single-core CPU exhaustion and application-level denial of service.

Amit Schendel
Amit Schendel
3 views•10 min read
•about 2 hours ago•CVE-2026-126304
8.7

CVE-2026-126304: Symlink Path Traversal in NLTK YCOECorpusReader

CVE-2026-126304 is a symlink path traversal vulnerability (CWE-59) in the Natural Language Toolkit (NLTK) versions 3.10.0 prior to 3.10.4. The YCOECorpusReader class constructs internal sub-readers for the 'psd' and 'pos' subdirectories using FileSystemPathPointer.join(), which relies exclusively on lexical string-prefix validation rather than canonical path resolution. An attacker who supplies a crafted YCOE corpus containing symbolic links in place of the 'psd' or 'pos' subdirectories can bypass directory confinement and read arbitrary files from sibling corpora or sensitive directories within the NLTK data sandbox.

Amit Schendel
Amit Schendel
4 views•9 min read
•about 3 hours ago•CVE-2026-128077
6.5

CVE-2026-128077: Authorization Bypass via Request Path Desynchronization in Nuxt and @nuxt/nitro-server

CVE-2026-128077 (GHSA-r99w-jh2x-3mg9) is an authorization bypass and interpretation conflict vulnerability affecting Nuxt and its underlying @nuxt/nitro-server package in versions 4.6.0 through 4.6.3. When an incoming HTTP request path begins with a double forward slash (e.g., //x/admin), the WHATWG URL parser within the Nuxt server-side page renderer interprets the initial segment as a network host/authority and resolves the remaining path (/admin) against the application's page router. Because Nitro server middleware, route-scoped serverHandlers, and Nitro routeRules evaluate the unparsed request path (//x/admin), path-based access controls, redirects, and security header policies configured for /admin fail to match and are bypassed.

Amit Schendel
Amit Schendel
5 views•10 min read
•about 4 hours ago•CVE-2026-128084
4.8

CVE-2026-128084: Integer Truncation and SQL Query Truncation in sqlite3-ruby

Prior to version 2.10.2, the sqlite3-ruby gem explicitly cast 64-bit Ruby string lengths (long) to 32-bit signed integers (int) when invoking the underlying SQLite C API. On 64-bit platforms, providing a string of 4 GiB (2^32 bytes) or larger causes integer truncation, instructing SQLite to process only a prefix of the string. This flaw affects SQL query preparation, bound parameter values, and return values from custom Ruby-defined SQL functions and aggregates, allowing trailing SQL clauses such as WHERE restrictions to be silently dropped under specific conditions.

Alon Barad
Alon Barad
5 views•11 min read
•about 5 hours ago•CVE-2026-128068
5.3

CVE-2026-128068: Regular Expression Denial of Service in rails-html-sanitizer

CVE-2026-128068 (GHSA-cpgf-5mjf-73p7) is a Regular Expression Denial of Service (ReDoS) vulnerability in the rails-html-sanitizer Ruby gem affecting versions 1.0.3 through 1.7.1. The flaw resides in the Rails::HTML::PermitScrubber#scrub_attribute method, which uses the multiline regular expression /^\s*[^#\s].*/m to enforce local-only URI fragment references on SVG elements. On Ruby runtimes prior to version 3.2 (CRuby <= 3.1 and JRuby), evaluating an attribute value composed of repeated newline and whitespace characters without a hash character triggers quadratic backtracking O(n^2). Applications are only vulnerable if their sanitization allowlist is explicitly configured to permit SVG reference elements such as <use> alongside href or xlink:href attributes.

Alon Barad
Alon Barad
6 views•9 min read
•about 6 hours ago•CVE-2026-126360
5.3

CVE-2026-126360: Regular Expression Denial of Service in OpenTelemetry Python opentelemetry-api

CVE-2026-126360 (GHSA-mf5v-w3w3-f6cg) is an algorithmic complexity vulnerability (Regular Expression Denial of Service) in the trace context propagation logic of the opentelemetry-api package within the OpenTelemetry Python ecosystem. In versions prior to 1.45.2, the TraceContextTextMapPropagator.extract() method utilizes a regular expression susceptible to quadratic-time backtracking when parsing malformed W3C traceparent headers containing long sequences of whitespace followed by an embedded newline character. In Python applications—particularly those using single-threaded asynchronous event loops—an unauthenticated remote attacker transmitting payloads over newline-preserving carriers can monopolize CPU execution and induce application-level Denial of Service.

Alon Barad
Alon Barad
5 views•10 min read