This is less a front-door smash and more a valet handing every guest the same parking ticket
CVE-2025-21618 is an *improper authentication/session isolation* flaw in NiceGUI On Air, the framework's remote-sharing feature. In affected nicegui versions <=2.9.0, once one user authenticates to an app exposed through On Air, other browsers—including incognito sessions—can inherit that authenticated state. The vendor fixed it in 2.9.1, and the patch shows the root cause plainly: shared client cookies were being retained between On Air requests.
The vendor's HIGH 7.5 score is technically understandable if you score this as generic unauthenticated network auth bypass. In the real world, it overstates enterprise urgency because exploitation depends on a narrower setup: the app must be using ui.run(on_air=True) or an On Air token, the app must actually rely on NiceGUI auth, and the exposed population is far smaller than ordinary web apps. This is a real bug, but for most estates it is a *demo/tunnel edge-case*, not a Monday-morning fleet fire.
4 steps from start to impact.
Find a live On Air app
ui.run(on_air=True) or a persistent On Air token, creating a public URL reachable over the internet. Tooling is trivial here: a normal browser or curl is enough; no exploit framework is required. Reference: NiceGUI On Air docs.- Target uses NiceGUI
- Target explicitly enabled NiceGUI On Air
- Attacker can reach the generated public URL
- On Air is optional and described as a *tech preview*, so most enterprise NiceGUI deployments will not use it
- Many internal NiceGUI apps are local-only or reverse-proxied normally, not published via On Air
Wait for a legitimate login
- Application actually implements authentication with NiceGUI
- At least one real user logs in to the same exposed On Air app
- If the app has no auth, there is nothing to bypass
- If no one logs in, the bug never amplifies into unauthorized access
- Single-user demos or low-traffic tools may never present an exploitable moment
Inherit authenticated state
self.client.cookies.clear() after each response, confirming cookie persistence was the core defect. A browser is sufficient to weaponize this; the 'exploit' is simply browsing the app after another user authenticates. Reference: fix commit.- Vulnerable version is installed
- On Air request handling still shares cookie state
- Blast radius is usually limited to that one app/session context, not host compromise
- Impact depends on what the app lets an authenticated user do
Abuse application-level privileges
- Authenticated user role has meaningful permissions in the app
- No evidence this crosses tenant boundaries beyond the exposed app
- No code execution or server takeover is implied by the advisory
The supporting signals.
| In-the-wild status | No authoritative evidence of active exploitation found in CISA KEV or vendor materials as of this assessment. |
|---|---|
| KEV status | Not listed in the CISA Known Exploited Vulnerabilities Catalog. |
| PoC availability | No standalone public exploit repo surfaced in primary-source review. The best public reproduction artifact is the vendor/GitHub advisory description plus the one-line fix in nicegui/air.py. |
| EPSS | User-supplied EPSS is 0.00172; third-party rollups around this CVE show roughly ~33rd percentile, which is *low* relative exploitation likelihood, not breakout behavior. |
| CVSS meaning | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N scores like a broad internet auth bypass, but the vector misses the real deployment friction: On Air must be enabled first. |
| Affected versions | GitHub advisory says <=2.9.0; NVD says 'prior to 2.9.1'. Operationally, treat all nicegui releases through 2.9.0 as affected *when On Air is used*. |
| Fixed version | Upgrade to 2.9.1 or later. No distro backport evidence surfaced in the primary sources reviewed; this looks like a normal PyPI/library upgrade case. |
| Exposure population | Exposure is not 'all NiceGUI apps'; it is the subset explicitly launched with NiceGUI On Air. The vendor docs describe On Air as an optional public-sharing feature and *tech preview*, which sharply narrows reachable population. |
| Root cause | The patch added self.client.cookies.clear() after each response to stop HTTP client cookie persistence leaking from one On Air request into another. |
| Disclosure | Published 2025-01-06 by GitHub Security Advisory GHSA-v6jv-p6r8-j78w; NVD still shows the record as not enriched by NVD itself. |
noisgate verdict.
The decisive downward pressure is attacker reachability: this bug matters only where organizations deliberately exposed a NiceGUI app through the optional On Air tunnel feature. That sharply shrinks the victim pool compared with a normal internet-facing auth bypass, even though exploitation on an exposed app is easy once a real user logs in.
Why this verdict
- Vendor baseline starts high because it is a no-auth network-reachable authentication failure with integrity impact once reachable.
- Major friction: optional feature exposure. The attacker position is only 'unauthenticated remote' *if* the target explicitly enabled NiceGUI On Air; otherwise the bug is unreachable from the internet. That implication alone cuts real-world exposed population hard.
- Second friction: requires a legitimate login event. The attacker typically needs another user to authenticate first, which makes this more like session bleed than a self-contained pre-auth break-in.
- Third friction: application-scoped blast radius. Impact is limited to what that one NiceGUI app exposes; there is no evidence of framework-to-host compromise, RCE, or cross-estate takeover.
- Low threat intel pressure. No KEV listing, no primary-source evidence of campaigns, and a low EPSS signal all argue against keeping the vendor 7.5 intact.
Why not higher?
If this were a default-on web admin surface or a broadly exposed SaaS control plane, the vendor HIGH would stand. But this vulnerability lives behind an optional relay feature and a specific auth usage pattern, which means the exposed population is much smaller than the CVSS vector implies.
Why not lower?
This is still a *real* authentication bypass on publicly reachable apps that use On Air, and exploitation is operationally simple once the conditions are present. For teams that do use On Air for demos, robotics, support, or ad hoc remote access, the impact can be immediate unauthorized access to authenticated functions.
What to do — in priority order.
- Disable
on_airwhere you do not absolutely need it — Remove the vulnerable exposure path entirely by stopping use ofui.run(on_air=True)or persistent On Air tokens on affected apps. For a MEDIUM verdict there is no noisgate mitigation SLA, but this is the fastest risk reduction for any internet-exposed demo or operator console. - Gate remote access with your own reverse proxy instead — If the app must be remotely reachable, publish it through your standard ingress stack with SSO, MFA, IP allowlists, and logging instead of the built-in On Air relay. Again, no mitigation SLA for MEDIUM; implement during normal remediation planning, sooner for externally shared apps.
- Inventory NiceGUI packages in CI and hosts — Use SBOM/SCA or package inventory to find
nicegui <=2.9.0, then manually confirm which instances actually use On Air. For MEDIUM, there is no separate mitigation deadline—fold this straight into the remediation workflow before the 365-day patch window closes. - Alert on authenticated access without matching login events — For apps you cannot patch immediately, add temporary application logging or proxy correlation to catch browsers gaining authenticated pages without an associated auth event. This is detective-only, not preventive, but it gives you a way to spot live abuse while you remediate.
- Generic EDR does not stop this; the abuse happens inside normal web traffic and the browser/app session layer.
- Password complexity or resets do not fix shared-session leakage; the issue is cookie isolation in On Air request handling, not weak credentials.
- A WAF is unlikely to help because there is no malicious payload pattern to block—just ordinary requests benefiting from bad session handling.
Crowdsourced verification payload.
Run this on the target host, container image, venv, or CI build environment where nicegui is installed. Invoke it with python3 check_nicegui_cve_2025_21618.py; no admin privileges are needed, but it must run in the same Python environment as the app package.
#!/usr/bin/env python3
"""
Check for CVE-2025-21618 in nicegui.
Outputs one of: VULNERABLE / PATCHED / UNKNOWN
Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
"""
import sys
import os
import re
from pathlib import Path
try:
from importlib import metadata as importlib_metadata
except Exception:
import importlib_metadata # type: ignore
def parse_version(v):
nums = []
for part in re.findall(r"\d+", v):
try:
nums.append(int(part))
except ValueError:
nums.append(0)
while len(nums) < 3:
nums.append(0)
return tuple(nums[:3])
def main():
try:
version = importlib_metadata.version('nicegui')
except importlib_metadata.PackageNotFoundError:
print('UNKNOWN: nicegui is not installed in this Python environment')
sys.exit(2)
except Exception as e:
print(f'UNKNOWN: unable to read installed package metadata: {e}')
sys.exit(2)
installed = parse_version(version)
vulnerable_floor = (0, 0, 0)
fixed = (2, 9, 1)
# Try to inspect the installed source to detect source/backport fixes.
source_check = None
try:
import nicegui.air as air # type: ignore
air_file = Path(getattr(air, '__file__', ''))
if air_file and air_file.exists():
text = air_file.read_text(encoding='utf-8', errors='ignore')
if 'self.client.cookies.clear()' in text:
source_check = 'patched'
else:
source_check = 'not_patched'
except Exception:
source_check = None
if source_check == 'patched':
print(f'PATCHED: nicegui {version} has the cookie-clear fix present in air.py')
sys.exit(0)
if vulnerable_floor <= installed < fixed:
print(f'VULNERABLE: nicegui {version} is older than 2.9.1 and no backport fix was detected')
sys.exit(1)
if installed >= fixed:
print(f'PATCHED: nicegui {version} is 2.9.1 or newer')
sys.exit(0)
print(f'UNKNOWN: unable to determine CVE-2025-21618 status for nicegui {version}')
sys.exit(2)
if __name__ == '__main__':
main()
If you remember one thing.
nicegui <=2.9.0 and identify which apps are launched with on_air; for those exposed apps, disable On Air or move them behind your normal authenticated ingress as a practical temporary control, but because this is MEDIUM there is no noisgate mitigation SLA — go straight to the 365-day remediation window. Your noisgate remediation SLA is to upgrade affected NiceGUI instances to 2.9.1+ within 365 days, while any externally shared demo or operations app using On Air should be remediated much sooner based on business exposure.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.