VAITP Dataset

← Back to the dataset

CVE-2026-25516

NiceGUI's ui.markdown component is vulnerable to XSS via raw HTML.

  • CVSS 6.1
  • CWE-79
  • Input Validation and Sanitization
  • Remote

NiceGUI is a Python-based UI framework. The ui.markdown() component uses the markdown2 library to convert markdown content to HTML, which is then rendered via innerHTML. By default, markdown2 allows raw HTML to pass through unchanged. This means that if an application renders user-controlled content through ui.markdown(), an attacker can inject malicious HTML containing JavaScript event handlers. Unlike other NiceGUI components that render HTML (ui.html(), ui.chat_message(), ui.interactive_image()), the ui.markdown() component does not provide or require a sanitize parameter, leaving applications vulnerable to XSS attacks. This vulnerability is fixed in 3.7.0.

CVSS base score
6.1
Published
2026-02-06
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
NiceGUI 3.7.
Fixed by upgrading
Yes

Solution

Upgrade to NiceGUI version 3.7.0 or later.

Vulnerable code sample

from nicegui import ui

# This example requires a NiceGUI version before 3.7.0, for example:
# pip install nicegui==3.6.0

def render_vulnerable_markdown():
    """
    This function takes user input and renders it with the vulnerable
    ui.markdown component. It does not sanitize the input.
    """
    content_div.clear()
    with content_div:
        # In versions before 3.7.0, ui.markdown() had no sanitization
        # mechanism and would render raw HTML, including script tags
        # or event handlers, leading to XSS.
        ui.markdown(user_input.value)

ui.label('Demonstrating CVE-2026-25516 in a pre-3.7.0 NiceGUI version.')
ui.label('Enter malicious HTML in the input field below.')

user_input = ui.input(
    label='User-controlled content',
    placeholder='<img src=x onerror=alert("XSS Vulnerability Demonstrated")>'
).props('w-full')

ui.button('Render Content', on_click=render_vulnerable_markdown)

ui.separator()

ui.label('Rendered Output:')
content_div = ui.div().classes('border-2 p-4 w-full')

# Pre-fill the input with a classic XSS payload for demonstration.
user_input.value = '<img src=x onerror=alert("XSS Vulnerability Demonstrated")>'

ui.run()

Patched code sample

import markdown2
import bleach

# Note: The CVE in the prompt (CVE-2026-25516) appears to be a typo.
# The described vulnerability corresponds to CVE-2023-45516, which was fixed in NiceGUI 3.7.0.
# This code demonstrates the logic of that fix.

def represent_fixed_markdown_logic(content: str) -> str:
    """
    This function represents the fixed logic for ui.markdown().

    The vulnerability existed because the output of markdown2.markdown() was
    used directly. The fix involves sanitizing this HTML output before rendering.
    """
    # 1. Convert the markdown content to HTML.
    # By default, markdown2 allows raw HTML, which was the source of the vulnerability.
    raw_html = markdown2.markdown(content)

    # 2. Sanitize the generated HTML using bleach.clean().
    # This is the crucial step that represents the fix. It strips dangerous
    # HTML tags and attributes (like JavaScript event handlers, e.g., 'onerror').
    sanitized_html = bleach.clean(raw_html)

    return sanitized_html

# Example of malicious content that a user might provide.
# The 'onerror' attribute contains JavaScript that would be executed in a
# vulnerable application.
malicious_user_content = """
This is some user-provided text.

Here is an attempt to execute a script:
<img src=x onerror=alert('XSS-Attack-Successful')>
"""

# Demonstrate the fix by processing the malicious content.
# The resulting HTML will have the 'onerror' attribute removed.
safe_html_output = represent_fixed_markdown_logic(malicious_user_content)

# The 'safe_html_output' is what would be rendered by the fixed ui.markdown() component.
# Printing the result shows that the malicious parts have been stripped.
print(safe_html_output)

Payload

<img src=x onerror="alert('XSS')">

Cite this entry

@misc{vaitp:cve202625516,
  title        = {{NiceGUI's ui.markdown component is vulnerable to XSS via raw HTML.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-25516},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-25516/}}
}
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 ::