Wysoka

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

  • Ujawniono: 02.09.2026
  • Aktualizacja: 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.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Python (PyPI) mistune >= 3.3.0, < 3.3.3 3.3.3

Odnośniki

Ocena CVSS 7.5/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Słabość (CWE)
CWE-674
Platforma
Python (PyPI)
Paczka
mistune
Ujawniono
02.09.2026
Aktualizacja
11.10.2026 15:18

Źródła i licencje

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

Historia podatności: mistune

Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (20) w archiwum
Wszystkich wpisów
20
Pierwsza → ostatnia
10.2017 09.2026
Bez poprawki
1
Wykorzystywana w atakach
0

Rozkład istotności

  • Wysoka 7
  • Średnia 13

Ujawnienia w latach

  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
Istotność:
  1. Mistune: Denial of Service — RecursionError via Excessive Emphasis Markers in Markdown ten wpis
    Wysoka · 7.5 CVE-2026-76098 >= 3.3.0, < 3.3.3 3.3.3
  2. Wysoka · 8.6 CVE-2022-34749 >= 2.0.0a1, < 2.0.3 2.0.3

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.