Hoch

Mistune: Denial of Service — RecursionError via Excessive Emphasis Markers in Markdown

  • Veröffentlicht: 02.09.2026
  • Aktualisiert: 11.10.2026 15:18

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 _process_emphasis_delimiters() 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.render_token() method (src/mistune/renderers/html.py:40-57) renders these tokens recursively: when a token has children, line 48 calls self.render_tokens(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 render_token(self, token: Dict[str, Any], state: BlockState) -> str:
    func = self._get_method(token["type"])
    attrs = token.get("attrs")
    if "raw" in token:
        text = token["raw"]
    elif "children" in token:
        text = self.render_tokens(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 render_tokens() 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 max_nested_level mechanism (currently at DEFAULT_MAX_NESTED_LEVEL = 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.

Betroffene Software

Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.

PlattformPaketAnfällige VersionenBehoben in
Python (PyPI) mistune >= 3.3.0, < 3.3.3 3.3.3

Verweise

CVSS-Wert 7.5/10
CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Schwäche (CWE)
CWE-674
Plattform
Python (PyPI)
Paket
mistune
Veröffentlicht
02.09.2026
Aktualisiert
11.10.2026 15:18

Quellen und Lizenzen

OSV / GitHub Advisory Database - PYSEC-2026-3863 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-6m44-fpc8-c3rq - CC BY 4.0

Schwachstellenhistorie: mistune

Alle veröffentlichten Schwachstellen dieses Pakets (Python (PyPI)), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.

Alle (20) im Archiv
Einträge insgesamt
20
Erste → letzte
10.2017 09.2026
Ohne Fix
1
In Angriffen ausgenutzt
0

Verteilung nach Schweregrad

  • Hoch 7
  • Mittel 13

Veröffentlichungen pro Jahr

  1. 2017: 2
  2. 2018: 0
  3. 2019: 0
  4. 2020: 0
  5. 2021: 0
  6. 2022: 1
  7. 2023: 0
  8. 2024: 0
  9. 2025: 0
  10. 2026: 17
Schweregrad:
  1. Mistune: Denial of Service — RecursionError via Excessive Emphasis Markers in Markdown dieser Eintrag
    Hoch · 7.5 CVE-2026-76098 >= 3.3.0, < 3.3.3 3.3.3
  2. Hoch · 8.6 CVE-2022-34749 >= 2.0.0a1, < 2.0.3 2.0.3

Erkennen Sie Schwachstellen in Ihrer Anwendung

Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.

Anwendung verbinden
DockRay Newsletter

Anwendungssicherheit in Ihrem Postfach

Wichtige Schwachstellen, konkrete Empfehlungen und praktische Tipps für Ihre Anwendungen. Wählen Sie Ihre Technologien und verfolgen Sie, was für Ihr Projekt relevant ist.

  • Eine tägliche Zusammenfassung neuer Schwachstellen, auch kritischer.
  • Benachrichtigungen über wichtige Updates.
  • Praktische Tipps zur Sicherheit und Überwachung von Anwendungen.

Leer lassen, um Meldungen zu allen Technologien zu erhalten.

Kostenlos anmelden. In jeder E-Mail mit einem Klick abmelden.