CVE-2026-33079: mistune: ReDoS exposes Jupyter/AI services to DoS
GHSA-8mp2-v27r-99xp HIGH CISA: TRACK*A crafted 58-byte Markdown string triggers exponential regex backtracking in mistune's link title parser (LINK_TITLE_RE), freezing the Python process for ~6 seconds per 25 escape pairs — with time doubling per additional byte pair, requiring no authentication and no exploit tooling beyond a public PoC. With 1,862 downstream dependents and explicit impact on Jupyter/nbconvert — a cornerstone of AI/ML data pipelines and notebook-based development environments — any service that passes untrusted Markdown through mistune is a target for availability attacks. Although not in CISA KEV, the 97th-percentile EPSS rank signals above-average exploitation likelihood relative to the CVE population, and the trivially replicable payload (under 100 bytes, zero specialized knowledge required) makes this easy to weaponize at scale against multi-tenant AI platforms. Upgrade mistune to 3.2.1 immediately and audit all transitive dependencies (especially nbconvert and Jupyter components) for exposure.
What is the risk?
MEDIUM-HIGH for AI/ML organizations. Exploitability is trivial: the public PoC requires no privileges, no authentication, and only a sub-100-byte input to cause a 6+ second block on a modern M2 processor, with exponential scaling beyond that. The blast radius is significant — 1,862 downstream dependents and confirmed impact on Jupyter notebook tooling, which is deeply embedded in AI/ML development and data science workflows. Impact is limited to availability (no RCE, no data exfiltration), which constrains overall severity, but the potential for cascading service disruption in shared Python worker pools elevates operational risk. A clear patch (3.2.1) is available, reducing residual risk substantially for teams that apply it promptly.
How does the attack unfold?
What systems are affected?
How severe is it?
What should I do?
5 steps-
IMMEDIATE
Upgrade mistune to 3.2.1 via 'pip install mistune>=3.2.1'. The fix excludes the backslash from the catch-all character class, eliminating alternation ambiguity and reducing N=25 processing from 5.9s to <0.000008s (700,000x improvement).
-
AUDIT DEPENDENCIES
Run 'pip list | grep mistune' across all environments; check transitive pulls via nbconvert and Jupyter components.
-
DETECT EXPOSURE
Search codebase and CI for 'import mistune' or 'from mistune' and flag any path that accepts user-supplied strings.
-
COMPENSATING CONTROL (if patching is delayed): Enforce strict maximum length limits on Markdown inputs (e.g., 5–10KB cap) and run the parser in a subprocess with a hard timeout (e.g., 2 seconds via Python's 'signal.alarm' or 'concurrent.futures').
-
MONITOR
Alert on sustained CPU spikes in Python workers during Markdown parsing events and flag inputs containing 8+ consecutive backslash-character pairs (regex pattern: '(\\[^"\x00]){8,}').
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-33079?
A crafted 58-byte Markdown string triggers exponential regex backtracking in mistune's link title parser (LINK_TITLE_RE), freezing the Python process for ~6 seconds per 25 escape pairs — with time doubling per additional byte pair, requiring no authentication and no exploit tooling beyond a public PoC. With 1,862 downstream dependents and explicit impact on Jupyter/nbconvert — a cornerstone of AI/ML data pipelines and notebook-based development environments — any service that passes untrusted Markdown through mistune is a target for availability attacks. Although not in CISA KEV, the 97th-percentile EPSS rank signals above-average exploitation likelihood relative to the CVE population, and the trivially replicable payload (under 100 bytes, zero specialized knowledge required) makes this easy to weaponize at scale against multi-tenant AI platforms. Upgrade mistune to 3.2.1 immediately and audit all transitive dependencies (especially nbconvert and Jupyter components) for exposure.
Is CVE-2026-33079 actively exploited?
No confirmed active exploitation of CVE-2026-33079 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-33079?
1. IMMEDIATE: Upgrade mistune to 3.2.1 via 'pip install mistune>=3.2.1'. The fix excludes the backslash from the catch-all character class, eliminating alternation ambiguity and reducing N=25 processing from 5.9s to <0.000008s (700,000x improvement). 2. AUDIT DEPENDENCIES: Run 'pip list | grep mistune' across all environments; check transitive pulls via nbconvert and Jupyter components. 3. DETECT EXPOSURE: Search codebase and CI for 'import mistune' or 'from mistune' and flag any path that accepts user-supplied strings. 4. COMPENSATING CONTROL (if patching is delayed): Enforce strict maximum length limits on Markdown inputs (e.g., 5–10KB cap) and run the parser in a subprocess with a hard timeout (e.g., 2 seconds via Python's 'signal.alarm' or 'concurrent.futures'). 5. MONITOR: Alert on sustained CPU spikes in Python workers during Markdown parsing events and flag inputs containing 8+ consecutive backslash-character pairs (regex pattern: '(\\[^"\x00]){8,}').
What systems are affected by CVE-2026-33079?
This vulnerability affects the following AI/ML architecture patterns: Jupyter notebook environments, LLM chat interfaces with Markdown rendering, AI documentation and model hub platforms, API endpoints processing user-supplied Markdown, ML CI/CD pipelines using nbconvert for notebook testing.
What is the CVSS score for CVE-2026-33079?
No CVSS score has been assigned yet.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.001 AI Software 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 A ReDoS (Regular Expression Denial of Service) vulnerability in `LINK_TITLE_RE` allows an attacker who can supply Markdown for parsing to cause denial of service. A crafted 58-byte Markdown document blocks the parser for approximately 6 seconds (measured on Apple M2, Python 3.14.3), with exponential growth per additional byte pair. ### Details The vulnerable regex is defined in [`src/mistune/helpers.py#L20-L25`](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/helpers.py#L20-L25): ```python LINK_TITLE_RE = re.compile( r"[ \t\n]+(" r'"(?:\\' + PUNCTUATION + r'|[^"\x00])*"|' # "title" r"'(?:\\" + PUNCTUATION + r"|[^'\x00])*'" # 'title' r")" ) ``` The double-quote branch compiles to `"(?:\\[PUNCTUATION]|[^"\x00])*"`. The two alternatives inside `(A|B)*` overlap: a backslash followed by a punctuation character (e.g. `\!`) can be matched by **either** branch — as a 2-character escaped-punctuation sequence `\\!`, or as two individual `[^"\x00]` characters (`\` then `!`). The same ambiguity exists in the single-quoted title branch. When the input contains repeated `\!` pairs with no closing `"`, the regex engine exhaustively backtracks through all 2^N combinations, resulting in **exponential O(2^N) time complexity**. This is reachable through normal Markdown parsing via two code paths: 1. **Inline links**: `[text](url "PAYLOAD)` → [`parse_link()`](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/helpers.py#L178) → [`parse_link_title()`](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/helpers.py#L169) 2. **Block link reference definitions**: `[label]: url "PAYLOAD` → [`BlockParser.parse_ref_link()`](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/block_parser.py#L220) → [`parse_link_title()`](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/helpers.py#L169) at [block_parser.py#L259](https://github.com/lepture/mistune/blob/df23edd60b43b639d2e6760ef9dd3d618aa11c21/src/mistune/block_parser.py#L259) ### PoC ```python import mistune import time md = mistune.create_markdown() # Test with increasing N (number of \! pairs) for n in [15, 18, 20, 22, 25]: payload = '[x](y "' + '\\!' * n + ')' start = time.time() md(payload) elapsed = time.time() - start print(f"N={n:2d} len={len(payload):3d} bytes time={elapsed:.3f}s") ``` Output (Apple M2, Python 3.14.3, mistune 3.2.0): ``` N=15 len= 38 bytes time=0.007s N=18 len= 44 bytes time=0.044s N=20 len= 48 bytes time=0.178s N=22 len= 52 bytes time=0.740s N=25 len= 58 bytes time=5.922s ``` Each increment of N roughly doubles the execution time (consistent with O(2^N)). The same attack works via block link reference definitions: ```python payload = '[l]: u "' + '\\!' * 25 # 58 bytes, ~6 seconds md(payload) ``` ### Impact This is a denial of service vulnerability. Any application or service that parses user-supplied Markdown using mistune can be made unresponsive by an attacker submitting a small crafted input (under 100 bytes). Affected use cases include: - Web applications with Markdown-enabled input fields (comments, posts, descriptions) - Documentation systems that accept user contributions - API endpoints that process Markdown - Jupyter tooling such as nbconvert that relies on mistune for rendering ### Suggested Fix Exclude the backslash character from the catch-all character class to eliminate the alternation overlap: ```python # Before (vulnerable): r'"(?:\\' + PUNCTUATION + r'|[^"\x00])*"' r"'(?:\\" + PUNCTUATION + r"|[^'\x00])*'" # After (fixed): r'"(?:\\' + PUNCTUATION + r'|[^"\\\x00])*"' r"'(?:\\" + PUNCTUATION + r"|[^'\\\x00])*'" ``` This ensures a backslash can only be consumed by the escaped-punctuation branch, eliminating the ambiguity in both the double-quote and single-quote branches. Verified on mistune 3.2.0 (Apple M2, Python 3.14.3): - Reduces N=25 from 4.2 seconds to 0.000006 seconds (700,000x improvement) - Handles N=50 in 0.000008 seconds - Passes all existing functional tests (quoted titles, escaped quotes, escaped punctuation)
Exploitation Scenario
An adversary targeting a multi-tenant AI platform (e.g., a notebook-sharing service, LLM chat interface, or model registry with Markdown-enabled description fields) discovers the target uses mistune for rendering. Without any authentication, the attacker submits POST requests to a public endpoint with Markdown body '[x](y "' + '\!' * 30 + ')' — 72 bytes total. Each request ties up a Python worker thread for 30+ seconds in exponential regex backtracking. By sending 10 concurrent such requests from a single IP or distributing across a botnet, the attacker exhausts all available workers, rendering the service completely unresponsive for legitimate users. In Jupyter environments, the same payload embedded in a notebook cell shared via a public URL freezes the kernel on open, enabling targeted disruption of ML researchers or CI/CD notebook-testing pipelines.
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
Timeline
Related Vulnerabilities
CVE-2023-25574 10.0 JupyterHub LTI13: JWT forgery enables full auth bypass
Same package: jupyter CVE-2026-44180 9.8 Jupyter Enterprise Gateway: root privilege bypass in Kubernetes
Same package: jupyter CVE-2026-42266 8.8 JupyterLab: Extension allow-list bypass enables privesc
Same package: jupyter CVE-2026-5422 8.1 jupyter-server: path traversal exposes sibling dir files
Same package: jupyter CVE-2025-30370 7.4 jupyterlab-git: command injection via malicious repo name
Same package: jupyter