CVE-2025-66469
Reflected XSS in NiceGUI's CSS functions allows arbitrary JS execution.
- CVSS 6.1
- CWE-79
- Input Validation and Sanitization
- Remote
NiceGUI is a Python-based UI framework. Versions 3.3.1 and below are vulnerable to Reflected XSS through its ui.add_css, ui.add_scss, and ui.add_sass functions. The functions lack proper sanitization or encoding for the JavaScript context they generate. An attacker can break out of the intended <style> or <script> tags by injecting closing tags (e.g., </style> or </script>), allowing for the execution of arbitrary JavaScript. This issue is fixed in version 3.4.0.
- CWE
- CWE-79
- CVSS base score
- 6.1
- Published
- 2025-12-09
- 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 to version 3.4.0 or later.
Vulnerable code sample
from nicegui import ui, app
@ui.page('/')
def vulnerable_page():
ui.label('Demonstration of Reflected XSS Vulnerability')
ui.markdown('This page is vulnerable to XSS via the `style` query parameter.')
# Retrieve potentially malicious input from the URL query string.
payload = app.storage.request.query.get('style')
if payload:
# In the vulnerable version, the 'payload' is passed directly to ui.add_css
# without any sanitization or encoding.
# An attacker can close the intended <style> tag and inject a <script> tag.
# Example Payload: </style><script>alert('XSS Vulnerability Executed')</script>
ui.add_css(payload)
ui.label('The following payload was injected:').classes('text-red-500')
ui.code(payload).classes('w-full')
else:
ui.label('To test the vulnerability, add a `style` query parameter to the URL.')
ui.link('Click here for a demonstration', '/?style=</style><script>alert("XSS")</script>')
# To test the vulnerability, run this script and navigate to a URL like:
# http://127.0.0.1:8080/?style=</style><script>alert("This is a demonstration of CVE-2025-66469")</script>
ui.run()Patched code sample
def _validate_css_for_injection(content: str) -> None:
"""
Prevents Reflected XSS by ensuring the provided content cannot break
out of the intended <style> context. This represents the core of the fix
for CVE-2025-66469.
It works by disallowing substrings that an attacker would use to close
the style tag and inject malicious script tags.
"""
# Use lowercase for case-insensitive matching
lower_content = content.lower()
# Block the primary injection vector: a closing style tag
if '</style>' in lower_content:
raise ValueError('CSS content is not allowed to contain "</style>".')
# As a defense-in-depth measure, also block closing script tags
if '</script>' in lower_content:
raise ValueError('CSS content is not allowed to contain "</script>".')
def add_css(content: str) -> None:
"""
Represents the fixed version of ui.add_css.
The fix is to call the validation function before any further processing.
"""
_validate_css_for_injection(content)
# ... original logic to add the validated CSS to the page would proceed here ...
def add_scss(content: str) -> None:
"""
Represents the fixed version of ui.add_scss.
The fix is to call the validation function before compilation and processing.
"""
_validate_css_for_injection(content)
# ... original logic to compile the validated SCSS and add it to the page would proceed here ...
def add_sass(content: str) -> None:
"""
Represents the fixed version of ui.add_sass.
The fix is to call the validation function before compilation and processing.
"""
_validate_css_for_injection(content)
# ... original logic to compile the validated SASS and add it to the page would proceed here ...Payload
</style><script>alert('XSS')</script>
Cite this entry
@misc{vaitp:cve202566469,
title = {{Reflected XSS in NiceGUI's CSS functions allows arbitrary JS execution.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-66469},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-66469/}}
}
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 ::
