CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-27156
6.1

NiceGUI CVE-2026-27156: When F-Strings Build Bridges to Hell

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 24, 2026·6 min read·5 visits

PoC Available

Executive Summary (TL;DR)

NiceGUI versions prior to 3.8.0 used Python f-strings to construct JavaScript commands and included an `eval()` fallback in the client-side code. This allows attackers to break out of string quotas or trigger arbitrary code execution via the `run_method` API.

A critical Cross-Site Scripting (XSS) vulnerability in NiceGUI allows attackers to execute arbitrary JavaScript by injecting malicious payloads into method names. The flaw stems from unsafe string interpolation in the Python backend and a dangerous `eval()` fallback in the JavaScript frontend.

The Hook: The Polyglot Trap

There is an old saying in security: the most dangerous place in any system is the boundary between two different languages. Whether it's SQL injection (Application vs. Database) or command injection (Application vs. Shell), the translation layer is where the bodies are buried. NiceGUI, a popular Python-based UI framework, attempts to bridge the gap between Python logic and the browser's JavaScript engine. It allows developers to control web elements purely from Python code.

It sounds magical. You write ui.button('Click me').on('click', handler), and the browser obeys. But under the hood, this magic relies on the server sending instructions to the client. Specifically, NiceGUI exposes APIs like run_method() that tell the frontend to execute specific JavaScript methods on DOM elements.

In CVE-2026-27156, we find out what happens when that communication channel is built with the digital equivalent of duct tape and optimism. It turns out that constructing executable code using string concatenation is—surprise, surprise—a terrible idea. This vulnerability transforms a feature meant for UI interactivity into a direct pipe for Cross-Site Scripting (XSS), allowing attackers to hijack the user's browser session with humiliating ease.

The Flaw: A Tale of Two Sins

The vulnerability is a beautiful, catastrophic duet between the backend and the frontend. It requires two distinct failures working in harmony to create the exploit condition.

Sin #1: The Python Interpolation

On the server side (Python), NiceGUI needs to tell the browser: "Hey, run the focus method on element #42." Prior to version 3.8.0, the code constructed this instruction using a Python f-string. It looked something like this:

f'return runMethod({self.id}, "{name}", ...)'

See the problem? The name variable is wrapped in double quotes. If an attacker can control name, they don't just provide a method name; they provide a string that creates code. By injecting a double quote ("), they can close the string context and start writing their own JavaScript. It is the classic "Bobby Tables" scenario, but for the browser.

Sin #2: The JavaScript Fallback

But wait, it gets worse. Even if you didn't break the string syntax, the frontend had a trapdoor waiting for you. The runMethod function in nicegui.js had a "helpful" fallback mechanism. If the method you requested didn't exist on the target element, the code decided to just eval() it.

Yes, you read that right. eval(method_name)(target, ...args). This meant that if you passed a global function name (like alert or a malicious payload defined elsewhere) instead of a valid element method, NiceGUI would helpfully execute it for you. It's like a bank vault that opens if you just ask it nicely in a different language.

The Code: Anatomy of the Patch

Let's look at the fix, because it perfectly illustrates the difference between "hacking it together" and "engineering." The developers at Zauberzeug (the maintainers) released a patch in version 3.8.0 that addresses both sides of the coin.

The Python Fix

In nicegui/element.py, the unsafe f-string was replaced with json.dumps(). This is the gold standard for passing data to JavaScript. json.dumps() ensures that quotes, backslashes, and control characters are properly escaped.

# The Vulnerable Way (Before)
return self.client.run_javascript(
    f'return runMethod({self.id}, "{name}", {json.dumps(args)})', 
    timeout=timeout
)
 
# The Secure Way (After)
return self.client.run_javascript(
    f'return runMethod({self.id}, {json.dumps(name)}, {json.dumps(args)})', 
    timeout=timeout,
)

The JavaScript Fix

In nicegui/static/nicegui.js, the patch is basically a deletion. They removed the eval() branch entirely. If the method doesn't exist on the element or its Quasar reference, the code now simply does nothing—which is exactly what it should do.

// nicegui.js diff
function runMethod(target, method_name, args) {
   // ... checks if method exists ...
-    } else {
-      return eval(method_name)(target, ...args); // Goodbye, old friend.
     }
   // ...

This creates a "defense in depth" posture. Even if the Python side somehow failed to escape the string (unlikely with json.dumps), the JS side no longer has the eval sink to abuse.

The Exploit: Breaking the Fourth Wall

So, how do we weaponize this? We need a scenario where a user-controlled input feeds into one of the affected APIs: run_method, run_grid_method, run_chart_method, or get_computed_prop.

Imagine a NiceGUI application that dynamically allows users to query properties of UI elements via a URL parameter, perhaps for a debugging dashboard or a dynamic report generator.

Attack Vector 1: Quote Breakout

If the application takes a query param ?action=... and passes it to run_method(action), we can send this payload:

"); alert(document.domain); //

The Python backend interpolates this into:

return runMethod(123, ""); alert(document.domain); //", ...)

The browser sees:

  1. Call runMethod with empty string.
  2. Execute alert(document.domain).
  3. Comment out the rest of the line (//).

Attack Vector 2: The Eval Fallback

If the quote injection is sanitized but the input still reaches the runMethod function, we can abuse the eval fallback (in versions < 3.8.0). If we control the method name, we can pass alert.

Even though alert isn't a method of the HTML Element, the else { return eval(method_name)(...) } block catches it. The browser resolves eval("alert") to the window's alert function and executes it. This is particularly dangerous because it bypasses checks that might only look for special characters like quotes or semicolons.

The Impact: Why You Should Care

NiceGUI is often used for internal dashboards, IoT control panels, and data science visualizations. These are environments that often sit behind a VPN but lack rigorous internal application security controls.

An XSS vulnerability here isn't just about popping an alert box. It allows an attacker to:

  1. Session Hijacking: Steal the session cookies of an administrator viewing the dashboard.
  2. RCE via Dashboard: Many of these dashboards control physical hardware or server-side processes. By hijacking a legitimate user's session, the attacker can trigger real-world actions (e.g., "Open Valve", "Reboot Server") using the victim's privileges.
  3. Worming: If the dashboard has a persistent state (like a shared log view), the XSS could be stored and executed by every engineer who logs in.

The CVSS score is 6.1 (Medium) mostly because it requires User Interaction (Reflected XSS), but in the context of trusted internal tools, the impact is often critical.

Mitigation: Patching the Hole

The remediation is straightforward: Upgrade to NiceGUI 3.8.0 or later immediately.

pip install --upgrade nicegui

If you cannot upgrade for some reason (maybe you enjoy living on the edge?), you must audit every single call to run_method and its siblings. Ensure that the name argument is never, ever derived from user input. Hardcode your method names.

For developers using the ui.run_javascript() escape hatch: The vulnerability in the core library serves as a warning. If you are manually constructing JavaScript strings using f-strings, stop it. Use json.dumps() for any variable you are injecting into a JS context. Do not trust your own ability to sanitize input; you will miss edge cases. Let the JSON library handle the serialization.

Official Patches

ZauberzeugCommit fixing unsafe f-string usage and removing eval fallback

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Affected Systems

NiceGUI < 3.8.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
nicegui
zauberzeug
< 3.8.03.8.0
AttributeDetail
CWE IDCWE-79
Attack VectorNetwork (Reflected)
CVSS v3.16.1 (Medium)
ImpactCross-Site Scripting (XSS)
Exploit StatusPoC Available
Fix Version3.8.0

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Cross-site Scripting

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Known Exploits & Detection

GitHub Security AdvisoryAdvisory containing description of the quote injection vector

Vulnerability Timeline

Vulnerability privately reported
2026-02-24
Patch developed and committed (v3.8.0)
2026-02-24
GitHub Advisory Published
2026-02-24

References & Sources

  • [1]GitHub Security Advisory GHSA-78qv-3mpx-9cqq
  • [2]NVD Entry for CVE-2026-27156

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.