Feb 24, 2026·6 min read·38 visits
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.
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 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.
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.
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:
runMethod with empty string.alert(document.domain).//).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.
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:
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.
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.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nicegui zauberzeug | < 3.8.0 | 3.8.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network (Reflected) |
| CVSS v3.1 | 6.1 (Medium) |
| Impact | Cross-Site Scripting (XSS) |
| Exploit Status | PoC Available |
| Fix Version | 3.8.0 |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.