
認証なしのパストラバーサルが fohrloop/dash-uploader(Python、PyPI)に存在し、任意のファイル書き込みが可能になります。これは、リモートコード実行(RCE)、アプリケーションのソースコード上書き、格納型XSS、永続的なバックドアのインストールなど(これらに限定されません)を引き起こします。
リポジトリは2025-07-19にアーカイブされ、アクティブなメンテナはいません。公開されている全バージョン(0.1.0 から 0.7.0a2)が影響を受け、今後も影響を受け続けます。このパッケージは現在も毎月約28,000ダウンロードされています。
本番環境で dash-uploader を稼働させている場合は、自ら緩和策を適用する必要があります。推奨される修正方法は、Plotly Dash に組み込まれている dcc.Upload コンポーネントへの移行です。すべての選択肢については緩和策を参照してください。
| CVE ID | CVE-2026-38360 (NVD) |
| 脆弱性 | パストラバーサル (CWE-22) |
| CVSS 3.1 | 9.8 / 緊急 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| 製品 | dash-uploader |
| 影響を受けるバージョン | 0.1.0 から 0.7.0a2(全18リリース) |
| 修正済みバージョン | なし(プロジェクトは2025-07-19にアーカイブ) |
| 攻撃ベクトル | リモート、認証不要 |
| 発見者 | Muhammad Fitri Bin Mohd Sultan |
| 割り当て元 | MITRE、2026-05-07 |
| 関連 | CVE-2026-38361(同一ライブラリのDoS) |
dash_uploader/httprequesthandler.py 内の request.form.get() から取得された3つのユーザー制御パラメータが、サニタイズや検証なしに os.path.join() と os.makedirs() に直接渡されます:
upload_id(57行目 → 161行目、BaseHttpRequestHandler.get_temp_root):保存先ディレクトリを制御します。攻撃者は upload_id=../../../../usr/local/lib/python3.10/site-packages を送信でき、ファイルがPythonのパッケージディレクトリに書き込まれます。
resumableFilename(51行目 → 108行目、BaseHttpRequestHandler._post):最終的なファイル名を制御します。攻撃者は正規の upload_id を使用した場合でも、ファイル名を通じてアップロードディレクトリの外へトラバーサルできます。
resumableIdentifier(54行目 → 64行目、BaseHttpRequestHandler._post):os.makedirs() とともに一時ディレクトリの作成に使用されます。攻撃者はファイルシステム上の任意の場所に任意のディレクトリを作成できます。
アップロードエンドポイント(デフォルトでは /API/dash-uploader)は認証を必要としません。v0.5.0 で追加された http_request_handler フックは、post_before() によるリクエスト前チェックを可能にしますが、脆弱性のある _post() メソッドはフックの戻り後にすべてのパラメータを request.form から直接読み取ります。フックは、ライブラリがパラメータを処理する前にサニタイズすることはできません。フックを介して認証を追加した開発者であっても、認証済みユーザーによるパストラバーサルの影響を受けます。
# dash_uploader/httprequesthandler.py
def _post(self):
resumableFilename = request.form.get("resumableFilename", default="error", type=str)
resumableIdentifier = request.form.get("resumableIdentifier", default="error", type=str)
upload_id = request.form.get("upload_id", default="", type=str)
...
temp_root = self.get_temp_root(upload_id) # upload_id flows in here
temp_dir = os.path.join(temp_root, resumableIdentifier) # raw user input -> os.path.join
if not os.path.isdir(temp_dir):
os.makedirs(temp_dir) # raw user input -> os.makedirs
def get_temp_root(self, upload_id):
return os.path.join(self.upload_folder, upload_id) # no sanitization: ../../ escapes upload_folder
3つの独立したトラバーサルシンクは同じ根本原因を共有しています:フォーム値が検証なしに os.path.join と os.makedirs に到達します。
認証されていないリモートの攻撃者は、HTTP POST multipart リクエストをアップロードエンドポイントに送信します。upload_id フォームパラメータにパストラバーサルシーケンス(../)を注入することで、攻撃者はアップロードされたファイルの保存先ディレクトリを制御できます。例えば、upload_id=../../../../usr/local/lib/python3.10/site-packages を送信すると、ファイルがPythonのパッケージディレクトリに書き込まれ、.pth の自動実行により次回のインタープリタ起動時にRCEが可能になります。
認証、セッショントークン、CSRFトークンは一切不要です。さらに2つのパラメータ(resumableFilename と resumableIdentifier)が、同じエンドポイントを通じて独立したトラバーサルベクトルを提供します。公式クイックスタートドキュメントに示されているデフォルトのライブラリ構成は、単一の curl コマンドで悪用可能です。
サーバープロセスが書き込み可能な任意のディレクトリへの任意のファイル書き込みが可能です。これは、いくつかのよく知られたプリミティブを通じて**リモートコード実行(RCE)**につながります:
RCEプリミティブ
.pth ファイルを site-packages に配置。次回のインタープリタ起動時に攻撃者指定のコードが実行されます。sitecustomize.py または usercustomize.py の注入。Python起動のたびに実行されます。app.wsgi、wsgi.py)を上書き。次回のワーカーリロード時に実行されます。/etc/cron.d/、/etc/cron.hourly/、ユーザーcrontabスプール)。スケジュール実行されます。/etc/systemd/system/、~/.config/systemd/user/)。次回のサービス起動時または再起動時に実行されます。/etc/ld.so.preload 注入。以降のすべてのバイナリ実行に攻撃者コードをプリロードします。~/.bashrc、~/.profile、~/.bash_profile)。アプリユーザーの次回の対話ログイン時に実行されます。~/.ssh/authorized_keys への追記。アプリユーザーとしてホストへの永続的なSSHアクセスを許可します。Web層への影響
site-packages 内のDashフレームワークJS)を上書きすることによる、ホストドメイン上の格納型クロスサイトスクリプティング。アプリケーションが再起動されるまで、すべてのページロードで全ユーザーに影響しますファイルシステムへの影響
resumableIdentifier パラメータを使用した os.makedirs() による、プロセスが到達可能な任意の場所への任意のディレクトリ作成(inode枯渇攻撃や、存在しないディレクトリツリーへの書き込みのステージングに使用可能)dash_uploader/httprequesthandler.pyBaseHttpRequestHandler.get_temp_root()BaseHttpRequestHandler._post()現在デプロイ中のユーザー向けの選択肢(推奨順):
dcc.Upload への移行:Plotly Dash に同梱されている公式のアップロードコンポーネントです。ファイルはコールバックにbase64文字列として届きます。ファイルシステムへ書き込むハンドラは公開されておらず、クライアントが制御する保存先パスも存在しないため、ここで説明するバグのクラスは該当しません。小〜中サイズのファイルに最適です。非常に大きなアップロードについては項目2を参照してください。
小さなFlaskアップロードハンドラを自作する:werkzeug.utils.secure_filename() と、ハードコードされたサーバー側の保存先ディレクトリを使用します。クライアントが指定した upload_id、ファイル名、identifier の値をパスコンポーネントとして受け入れてはなりません。
引き続きdash-uploaderを使用する場合:アップロードエンドポイントを認証の背後に配置し、さらに、ライブラリのハンドラがリクエストを参照する前にリクエストを書き換えるか拒否する層で、upload_id、resumableFilename、resumableIdentifier を厳格な許可リスト(例:UUIDのみ)に対して検証してください。ライブラリの http_request_handler フックは、フックの戻り後にパラメータが request.form から読み取られるため、トラバーサルを防ぎません。サニタイズはライブラリより上位の層で行う必要があります。
リバースプロキシまたはWAF層で、いずれかのフォームフィールドに ..、エンコードされた亜種(%2e%2e、..%2f、%2e%2e%2f)、または絶対パスを含むアップロードエンドポイントへのリクエストをすべて拒否します。
| 日付 | イベント |
|---|---|
| 2026-03-17 | 本番環境のデプロイに関するセキュリティ調査中に脆弱性を発見。 |
| 2026-03-19 | MITRE に CVE リクエストを提出。 |
| 2026-05-07 | MITRE により CVE-2026-38360 が割り当て。 |
| 2026-05-07 | 公開アドバイザリを公開。 |
| 2026-05-09 | CVE レコードが MITRE CVE データベース と NVD に公開。 |
0.6.1(安定版ライン)。プレリリースは 0.7.0a2 まで。dash。オプション依存:pyyaml。ライセンス:MIT。Muhammad Fitri Bin Mohd Sultan