Summary
NiceGUI バージョン 2.13.0 から 3.4.1 において、ui.navigate.history.push() または ui.navigate.history.replace() に攻撃者が制御可能な文字列を渡すと、XSS(クロスサイトスクリプティング)が発生する脆弱性が存在します。
これらのヘルパーはページリロードなしでブラウザURLを更新するHistory APIのラッパーとして文書化されていますが、URL引数が適切なエスケープなしに生成されたJavaScriptに埋め込まれるため、細工されたペイロードが意図した文字列コンテキストから抜け出し、被害者のブラウザで任意のJavaScriptを実行できます。
信頼できない入力を ui.navigate.history.push/replace に渡さないアプリケーションは影響を受けません。
Technical Details
脆弱性の種類
- CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
影響を受けるバージョン
- NiceGUI 2.13.0 - 3.4.1
修正バージョン
- NiceGUI 3.5.0
根本原因
NiceGUIは ui.navigate.history.push(url) と ui.navigate.history.replace(url) を提供し、ブラウザのHistory APIを使用してURLを更新します。アプリケーションがユーザー制御データ(例:URLパスセグメント、next=... のようなクエリパラメータ、フォーム値など)をこれらのメソッドに転送すると、攻撃者はクォートやステートメント終端子などの文字を注入してJavaScript文字列コンテキストから脱出し、任意のコードを実行できます。
脆弱なパターン:
- 攻撃者が値を制御(例:リクエストパス経由)
- アプリケーションがそれを
ui.navigate.history.push(payload)(またはreplace)に渡す
PoC
from nicegui import ui
@ui.page('/')
def index():
# 被害者がクリックする可能性のあるリンク/ボタン(攻撃者はURLを直接送信することも可能)
ui.button('open crafted path', on_click=lambda: ui.navigate.to('/%22);alert(document.domain);//'))
@ui.page('/{payload:path}')
def victim(payload: str):
ui.label(f'payload = {payload!r}')
# 脆弱な使用法:攻撃者が制御するパスをhistory.pushに転送
ui.button('trigger', on_click=lambda: ui.navigate.history.push(payload))
ui.run()
再現手順
http://localhost:8080/を開くopen crafted pathをクリックtriggerをクリック
結果:JavaScriptが実行される
Impact
- 脆弱性の種類: DOM-based XSS
- 攻撃ベクトル:
ui.navigate.history.push/replace経由でJavaScriptに埋め込まれた攻撃者制御の入力 - 影響を受けるユーザー: 信頼できない入力を
ui.navigate.history.push()またはui.navigate.history.replace()に転送するNiceGUIベースのアプリケーション - 潜在的な結果: クライアントサイドコード実行、フィッシングUI注入、その他の典型的なXSSの影響
CVSS
Score: 6.1 (Moderate)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Timeline
2026-01-08:Advisory published
2026-01-08:NiceGUI 3.5.0 released with fix