{"id":"PYSEC-2026-1701","summary":"NiceGUI apps are vulnerable to XSS which uses `ui.sub_pages` and render arbitrary user-provided links","details":"### Summary\n\nAn unsafe implementation in the `click` event listener used by `ui.sub_pages`, combined with attacker-controlled link rendering on the page, causes an XSS when the user actively clicks on the link. \n\n### Details\n\n1. On `click`, eventually `sub_pages_navigate` event is emitted.\nhttps://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/elements/sub_pages.js#L41-L63\n\n2. SubPagesRouter (used by ui.sub_pages), lisnening on `sub_pages_navigate`, `_handle_navigate` runs.\nhttps://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/sub_pages_router.py#L18-L22\n\n3. `_handle_navigate` runs `run_javascript` with f-string substituting `self.current_path` which is simply surrounded by double-quotes. The string context can be broken out easily. \n\nhttps://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/sub_pages_router.py#L73-L88\n\n### PoC\n\nThe minimal PoC boils down to this:\n\n```py\nfrom nicegui import ui\n\nui.sub_pages({'/': lambda: ui.link('Go to XSS', '/\"+alert(1)+\"')})\n\nui.run()\n```\n\nHowever, it is more likely that the attack takes place with attacker-controlled input, for which this shows it:\n\n```py\nfrom nicegui import app, ui\n\nui.sub_pages({'/': lambda: ui.label('Hello, World!')})\n\nui.textarea('Markdown content').bind_value(app.storage.general, 'markdown_content')\n\nui.markdown().bind_content_from(app.storage.general, 'markdown_content')\n\nui.run()\n```\n\nVulnerable input is `[XSS LINK](/\"+alert(document.domain)+\")` (causes double payload execution, though)\n\n**Both cases require someone to click on the link.** \n\n\u003cimg width=\"1428\" height=\"254\" alt=\"image\" src=\"https://github.com/user-attachments/assets/8be4f345-c0cf-4df2-9917-677a2ea72626\" /\u003e\n\n### Impact\n\nAny page which uses `ui.sub_pages` and renders arbitrary links on screen (common case of `ui.markdown`) is affected.\n\nThe impact is low since a click is always required from the user, who can on-hover to discover the sketchy content of the link and stop if well-trained. \n\n### Appendix\n\nAI is used safely to judge the CVSS scoring (input is not even provided, just the impact statement).\n\nPlease find the results in https://poe.com/s/y5DvyqgtszDGLUuHin1O\n\n### Scoring update after manual review\n\n- Scope **Changed** is more inline with other posted XSS vulnerabilities\n- Availability **None**: No DDoS is possible with this. Site remains performant as ever.","aliases":["CVE-2026-21872","GHSA-m7j5-rq9j-6jj9"],"modified":"2026-07-07T17:46:58.650836097Z","published":"2026-07-07T16:03:17.198320Z","references":[{"type":"WEB","url":"https://github.com/zauberzeug/nicegui/security/advisories/GHSA-m7j5-rq9j-6jj9"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-21872"},{"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-m7j5-rq9j-6jj9"}],"affected":[{"package":{"name":"nicegui","ecosystem":"PyPI","purl":"pkg:pypi/nicegui"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.22.0"},{"fixed":"3.5.0"}]}],"versions":["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-1701.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"}]}