GHSA-M7J5-RQ9J-6JJ9
Vulnerability from github – Published: 2026-01-08 20:08 – Updated: 2026-01-08 20:08Summary
An 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.
Details
-
On
click, eventuallysub_pages_navigateevent is emitted. https://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/elements/sub_pages.js#L41-L63 -
SubPagesRouter (used by ui.sub_pages), lisnening on
sub_pages_navigate,_handle_navigateruns. https://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/sub_pages_router.py#L18-L22 -
_handle_navigaterunsrun_javascriptwith f-string substitutingself.current_pathwhich is simply surrounded by double-quotes. The string context can be broken out easily.
https://github.com/zauberzeug/nicegui/blob/59fa9424c470f1b12c5d368985fa36e21fda706b/nicegui/sub_pages_router.py#L73-L88
PoC
The minimal PoC boils down to this:
from nicegui import ui
ui.sub_pages({'/': lambda: ui.link('Go to XSS', '/"+alert(1)+"')})
ui.run()
However, it is more likely that the attack takes place with attacker-controlled input, for which this shows it:
from nicegui import app, ui
ui.sub_pages({'/': lambda: ui.label('Hello, World!')})
ui.textarea('Markdown content').bind_value(app.storage.general, 'markdown_content')
ui.markdown().bind_content_from(app.storage.general, 'markdown_content')
ui.run()
Vulnerable input is [XSS LINK](/"+alert(document.domain)+") (causes double payload execution, though)
Both cases require someone to click on the link.
Impact
Any page which uses ui.sub_pages and renders arbitrary links on screen (common case of ui.markdown) is affected.
The 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.
Appendix
AI is used safely to judge the CVSS scoring (input is not even provided, just the impact statement).
Please find the results in https://poe.com/s/y5DvyqgtszDGLUuHin1O
Scoring update after manual review
- Scope Changed is more inline with other posted XSS vulnerabilities
- Availability None: No DDoS is possible with this. Site remains performant as ever.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.4.1"
},
"package": {
"ecosystem": "PyPI",
"name": "nicegui"
},
"ranges": [
{
"events": [
{
"introduced": "2.22.0"
},
{
"fixed": "3.5.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-21872"
],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-08T20:08:42Z",
"nvd_published_at": "2026-01-08T10:15:55Z",
"severity": "MODERATE"
},
"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({\u0027/\u0027: lambda: ui.link(\u0027Go to XSS\u0027, \u0027/\"+alert(1)+\"\u0027)})\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({\u0027/\u0027: lambda: ui.label(\u0027Hello, World!\u0027)})\n\nui.textarea(\u0027Markdown content\u0027).bind_value(app.storage.general, \u0027markdown_content\u0027)\n\nui.markdown().bind_content_from(app.storage.general, \u0027markdown_content\u0027)\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.",
"id": "GHSA-m7j5-rq9j-6jj9",
"modified": "2026-01-08T20:08:42Z",
"published": "2026-01-08T20:08:42Z",
"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"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "NiceGUI apps are vulnerable to XSS which uses `ui.sub_pages` and render arbitrary user-provided links"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.