CVE-2026-76098: Mistune has Denial of Service — RecursionError via Excessive Emphasis Markers in Markdown

Published Aug 24, 2026
·
Updated

Summary Mistune v3.3.2 is vulnerable to a Denial of Service (DoS) attack via uncontrolled recursion in the HTML rendering of deeply-nested emphasis tokens. By submitting Markdown containing approximately 1,000 consecutive asterisk characters, an attacker causes the Python process to crash with RecursionError.

Details The InlineParser's processemphasisdelimiters() creates deeply nested <strong> tokens from consecutive emphasis markers (every 2 asterisks add one nesting level). With 1,000 consecutive asterisks, approximately 500 levels of nesting are produced. The HTMLRenderer.rendertoken() method (src/mistune/renderers/html.py:40-57) renders these tokens recursively: when a token has children, line 48 calls self.rendertokens(token['children'], state), entering child rendering. Each nesting level produces ~2 stack frames, so 500 levels ≈ 1,000 frames, exceeding Python's default recursion limit (sys.getrecursionlimit() = 1000). The emphasis() and strong() methods (lines 80-84) wrap recursively rendered child content in <em> and <strong> tags, perpetuating the recursion. This vulnerability affects all mistune APIs including markdown() and html().

Core vulnerable code path:

python src/mistune/renderers/html.py:40-57 def rendertoken(self, token: Dict[str, Any], state: BlockState) -> str: func = self.getmethod(token["type"]) attrs = token.get("attrs") if "raw" in token: text = token["raw"] elif "children" in token: text = self.rendertokens(token["children"], state) else: if attrs: return func(attrs) else: return func() if attrs: return func(text, attrs) else: return func(text)

The recursive call to rendertokens() on line 48 processes nested child tokens. With 500 levels of nested emphasis/strong tokens, this recursion exceeds Python's default recursion limit of 1000, causing a RecursionError.

python src/mistune/renderers/html.py:80-84 def emphasis(self, text: str) -> str: return "<em>" + text + "</em>"

def strong(self, text: str) -> str: return "<strong>" + text + "</strong>"

The emphasis() and strong() methods wrap their text content (which is itself the recursively-rendered output of nested child tokens) in HTML tags, creating the chain of recursion: each call to strong() includes rendered children that themselves call strong(), etc.

POC

wiki from mistune import html

payload = '' 1000 try: result = html(payload) print('No crash - recursion handled') except RecursionError as e: print(f'[VULN] RecursionError: {e} - Process would crash!') except Exception as e: print(f'Error: {type(e).name}: {e}')

<img width="1139" height="664" alt="1" src="https://github.com/user-attachments/assets/d2095b9f-0a6a-4bef-8013-cbc6946cf8f1" />

Impact CVSS 3.1: 7.5 (High) — AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. An attacker can crash any server process using mistune with approximately 2KB of Markdown input. In web applications, this can be triggered through user-generated content such as forum posts or comments, causing denial of service for all concurrent users sharing the same Python process. Both mistune.markdown() and mistune.html() are affected.

Remediation 1. Add a maximum nesting depth limit in the emphasis parsing stage, similar to BlockParser's maxnestedlevel mechanism (currently at DEFAULTMAXNESTEDLEVEL = 20). When the limit is exceeded, treat excess emphasis markers as literal text. 2. Alternatively, refactor HTMLRenderer to use an explicit stack-based iterative approach instead of recursive calls for rendering nested tokens. 3. As a defense-in-depth measure, document the recursion risk and recommend that applications deploying mistune set a higher recursion limit or implement request-level timeouts.

Other sources

Mistune is a Python Markdown parser with renderers and plugins. Versions 3.3.0 through 3.3.2 are vulnerable to DoS through deeply nested tokens. HTML rendering creates deeply nested emphasis tokens from consecutive asterisk characters, and recursive rendering in HTMLRenderer.rendertoken() can exceed Python's recursion limit and raise RecursionError, allowing crafted Markdown to crash a parsing process. This issue is fixed in version 3.3.3

— NVD

Affected Software

3 affected componentsFixes available
Mistune Mistune>=3.3.0<=3.3.2
Mistune Mistune=3.3.3
pip/mistune>=3.3.0<3.3.3
3.3.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade pip/mistune to a version that resolves this vulnerability.

    Fixed in 3.3.3
  2. Upgrade

    Upgrade mistune to a version that resolves this vulnerability.

    Fixed in 3.3.3
  3. Compensating control

    As a defense-in-depth measure, document the recursion risk for mistune.emphasis/strong HTML rendering and ensure applications deploying mistune set an appropriately higher recursion limit and/or implement request-level timeouts to mitigate RecursionError/DoS risk when rendering crafted Markdown.

Event History

Aug 24, 2026
CVE Published
via MITRE·08:05 PM
Data Sourced
via MITRE·08:05 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·08:17 PM
DescriptionSeverityWeakness
Sep 2, 2026
Advisory Published
via GitHub·03:14 PM
Data Sourced
via GitHub·03:14 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who is exposed to this denial-of-service issue?

Applications using Mistune 3.3.0 through 3.3.2 to HTML-render Markdown are exposed when they process attacker-controlled Markdown. An unauthenticated remote attacker can supply crafted input to crash the parsing process.

2

What input is required to trigger the crash?

The attacker needs Markdown containing consecutive asterisk characters that produces deeply nested emphasis tokens. During HTML rendering, recursive token rendering can exceed Python's recursion limit and raise RecursionError.

3

Is upgrading available to remediate the issue?

Yes. The issue is fixed in Mistune version 3.3.3.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203