CVE-2025-53354
XSS in NiceGUI's ui.html() component due to unsanitized user input.
- CVSS 6.1
- CWE-79
- Input Validation and Sanitization
- Remote
NiceGUI is a Python-based UI framework. Versions 2.24.2 and below are at risk for Cross-Site Scripting (XSS) when developers render unescaped user input into the DOM using ui.html(). NiceGUI did not enforce HTML or JavaScript sanitization, so applications that directly combine components like ui.input() with ui.html() or ui.chat_message with HTML content without escaping may allow attackers to execute arbitrary JavaScript in the user’s browser. Applications that do not pass untrusted input into ui.html() are not affected. This issue is fixed in version 3.0.0.
- CWE
- CWE-79
- CVSS base score
- 6.1
- Published
- 2025-10-03
- 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
- Fixed by upgrading
- Yes
Solution
Upgrade NiceGUI to version 3.0.0 or later.
Vulnerable code sample
from nicegui import ui
# This application demonstrates the vulnerability.
# It takes user input and renders it directly into the DOM using ui.html()
# without any sanitization, which is the core issue described in the CVE.
def display_unsafe_content():
# The value from the input field is taken directly.
raw_user_content = text_input.value
# The vulnerability: The raw, untrusted user input is passed to ui.html().
# An attacker can input a string like '<script>alert("XSS Vulnerability")</script>'
# and it will be executed by the browser.
output_container.clear()
with output_container:
ui.html(f'Your message is: {raw_user_content}')
# The user interface setup
ui.label('Enter any text or an XSS payload like: <img src=x onerror=alert("XSS")>')
text_input = ui.input('Your message')
ui.button('Submit', on_click=display_unsafe_content)
ui.separator()
ui.label('Rendered Output:')
output_container = ui.column()
ui.run()Patched code sample
import html
from nicegui import ui
# The vulnerability described (CVE-2025-53354, which is hypothetical but mirrors
# the real CVE-2024-23341) stems from rendering unescaped user input via ui.html().
# The fix is not a change in the ui.html() function itself, but rather the
# developer's responsibility to sanitize or escape any untrusted input before
# passing it to ui.html(). The Python standard library `html.escape()` is the
# primary tool for this.
# This application demonstrates both the vulnerable pattern and the fixed pattern.
ui.label('Demonstration of XSS Fix').classes('text-2xl')
ui.markdown('Enter a string with HTML to see the difference. Try: `<strong>test</strong>` or `<img src=x onerror=alert("XSS")>`')
# Shared input for user data
user_input = ui.input(label='Enter potentially malicious input')
ui.separator().classes('my-4')
# --- VULNERABLE IMPLEMENTATION (for demonstration) ---
# This code represents the vulnerable pattern. The user's raw input is fed
# directly into ui.html(), which will render it as live HTML in the browser.
with ui.card().classes('w-full border-2 border-red-500'):
ui.label('Vulnerable Output').classes('text-lg font-bold text-red-700')
ui.label('The input is passed directly to ui.html() without escaping.')
vulnerable_display = ui.html()
vulnerable_display.bind_content_from(user_input, 'value')
ui.separator().classes('my-4')
# --- FIXED IMPLEMENTATION ---
# This code represents the fix. Before the user's input is rendered, it is
# passed through the `html.escape` function. This function converts special
# characters like '<', '>', '&' into their HTML entities ('<', '>', '&').
# As a result, the browser displays the string as plain text instead of
# interpreting it as HTML, mitigating the XSS risk.
with ui.card().classes('w-full border-2 border-green-500'):
ui.label('Fixed Output').classes('text-lg font-bold text-green-700')
ui.label('The input is sanitized with html.escape() before being rendered.')
fixed_display = ui.html()
fixed_display.bind_content_from(user_input, 'value', backward=html.escape)
ui.run()Payload
<script>alert('XSS')</script>
Cite this entry
@misc{vaitp:cve202553354,
title = {{XSS in NiceGUI's ui.html() component due to unsanitized user input.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-53354},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-53354/}}
}
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 ::
