{"id":"PYSEC-2026-1698","summary":"NiceGUI is vulnerable to XSS via Unescaped URL in ui.navigate.history.push() / replace()","details":"### Summary\nXSS risk exists in NiceGUI when developers pass attacker-controlled strings into `ui.navigate.history.push()` or `ui.navigate.history.replace()`. These helpers are documented as History API wrappers for updating the browser URL without page reload. However, if the URL argument is embedded into generated JavaScript without proper escaping, a crafted payload can break out of the intended string context and execute arbitrary JavaScript in the victim’s browser.\n\n**Applications that do not pass untrusted input into `ui.navigate.history.push/replace` are not affected.**\n\n### Details\nNiceGUI provides `ui.navigate.history.push(url)` and `ui.navigate.history.replace(url)` to update the URL using the browser History API. If an application forwards user-controlled data (e.g., URL path segments, query parameters like `next=...`, form values, etc.) into these methods, an attacker can inject characters such as quotes and statement terminators to escape the JavaScript string context and execute arbitrary code.\n\nA vulnerable pattern is:\n- attacker controls a value (e.g., via the request path),\n- the application passes it to `ui.navigate.history.push(payload)` (or `replace`).\n\nThis is similar in spirit to other NiceGUI XSS advisories:\n- `ui.html()`,`ui.chat_message()` can cause XSS when developers render untrusted input as HTML (XSS risk/footgun).\n- `ui.interactive_image` had XSS via unsanitized SVG content and was handled as a security advisory with a fix and severity rating.\n\nBecause `ui.navigate.history.*` is expected to accept a URL (data) rather than executable code, the library should escape/encode the argument before emitting JavaScript.\n\n### PoC\n#### Create a simple app\n\n```python\nfrom nicegui import ui\n\n@ui.page('/')\ndef index():\n    # A link/button a victim could click (attacker can also send the URL directly)\n    ui.button('open crafted path', on_click=lambda: ui.navigate.to('/%22);alert(document.domain);//'))\n\n@ui.page('/{payload:path}')\ndef victim(payload: str):\n    ui.label(f'payload = {payload!r}')\n\n    # Vulnerable use: forwarding attacker-controlled path to history.push\n    ui.button('trigger', on_click=lambda: ui.navigate.history.push(payload))\n\nui.run()\n```\n\n#### Run the app\n\n```bash\npython app.py\n```\n\n#### Trigger\n\n1. Open `http://localhost:8080/`\n2. Click `open crafted path`\n3. Click `trigger`\n\nExpected result: JavaScript executes (an alert showing `document.domain`).\n\n### Impact\n- Vulnerability type: DOM-based XSS\n- Attack vector: attacker-controlled input embedded into JavaScript via `ui.navigate.history.push/replace`\n- Affected users: any NiceGUI-based application that forwards untrusted input into `ui.navigate.history.push()` or `ui.navigate.history.replace()`\n- Potential outcomes: client-side code execution, phishing UI injection, and other typical XSS impacts","aliases":["CVE-2026-21871","GHSA-7grm-h62g-5m97"],"modified":"2026-07-07T17:46:58.212425247Z","published":"2026-07-07T16:03:17.124842Z","references":[{"type":"WEB","url":"https://github.com/zauberzeug/nicegui/security/advisories/GHSA-7grm-h62g-5m97"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-21871"},{"type":"PACKAGE","url":"https://github.com/zauberzeug/nicegui"},{"type":"WEB","url":"https://github.com/zauberzeug/nicegui/releases/tag/v3.5.0"},{"type":"PACKAGE","url":"https://pypi.org/project/nicegui"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-7grm-h62g-5m97"}],"affected":[{"package":{"name":"nicegui","ecosystem":"PyPI","purl":"pkg:pypi/nicegui"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.13.0"},{"fixed":"3.5.0"}]}],"versions":["2.13.0","2.14.0","2.14.1","2.15.0","2.16.0","2.16.1","2.17.0","2.18.0","2.19.0","2.20.0","2.21.0","2.21.1","2.22.0","2.22.1","2.22.2","2.23.0","2.23.1","2.23.2","2.23.3","2.24.0","2.24.1","2.24.2","3.0.0","3.0.0rc1","3.0.1","3.0.2","3.0.3","3.0.4","3.1.0","3.2.0","3.3.0","3.3.1","3.4.0","3.4.1"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/nicegui/PYSEC-2026-1698.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"}]}