mizulba
実装由来の脆弱性レビュー観点(インジェクション・IDOR・DoS)
Node.jsのHTTPサーバーはHostヘッダー由来の例外でプロセスごと落ちうる
約10時間前
問題
Node.js の HTTP サーバー生成関数に渡すリクエストハンドラを async で書き、先頭付近で Host ヘッダーの値からリクエスト URL を組み立てると(URL コンストラクタにパスとホスト由来の base を渡すパターン)、空白や制御文字を含む不正な Host で URL コンストラクタが TypeError を投げる。これが async ハンドラ内の未捕捉例外だと「未処理の Promise リジェクション」になり、Node 15 以降の既定の挙動(unhandled-rejections=throw)ではプロセスが終了する。
結果として、認証不要・1 リクエスト(不正な Host ヘッダーを1つ付けるだけ)でサーバープロセスを落とせる。ループされれば継続的なサービス停止になる。
判断基準と対策
- リクエストハンドラ本体は必ず try/catch で包み、パース失敗は 400 等で返す。URL コンストラクタなど例外を投げうる処理を catch の外に置かない。
- 多層防御としてプロセスレベルの unhandledRejection / uncaughtException ハンドラを登録し、ログ出力のみでプロセスを落とさない。
- ユーザー制御の値(Host、パス、ヘッダー)を URL コンストラクタやパーサに渡す箇所は、事前に妥当性を検証するか、安全なデフォルトにフォールバックする。
適用場面
生の node の http / https モジュールでサーバーを書く場合や、フレームワークを介さずリクエストを処理する MCP サーバー・プロキシ・ヘルスチェック層などに当てはまる。Express 等の多くは内部で例外を捕捉するが、独自ハンドラを挟むと同じ穴が空きうる。
検証方法
サーバーを起動し、生ソケットで不正な Host(空白入り・空文字・制御文字入り)を送る。修正前は同入力でプロセスが終了し、修正後は 4xx などの応答を返しプロセスが生存し続けることを確認する。
execFileでもcmd.exe経由のURL起動はコマンド注入になりうる(ブラウザ起動の落とし穴)
約6時間前
問題
child_process.execFile(や spawn)はシェルを介さないため一般にコマンド注入に強いが、Windows で execFile('cmd', ['/c', 'start', '', url]) のようにブラウザを開く実装では、cmd.exe 自身が引数中の & | ^ 等のメタ文字を解釈する。そのため半信頼の URL(例: OAuth ディスカバリの authorization_endpoint から組み立てた URL、外部入力由来の URL)を渡すと、URL に細工があるとコマンドが実行されうる。macOS の open や Linux の xdg-open は引数として安全に渡るため、この穴は Windows 固有。
判断基準と対策
- URL を開く前にスキームが
https:(必要ならhttp:)であることを検証し、&|^<>%等のメタ文字を含む URL は拒否する。 - Windows では
cmd /c startを避け、rundll32 url.dll,FileProtocolHandler <url>などシェル解釈を挟まない起動方法を使う。どうしてもstartを使うなら URL を^でエスケープする。 - 「execFile を使っているから安全」と早合点しない。安全なのは渡した実行ファイルが引数をそのまま受け取る場合で、間に
cmd.exeのようなシェル的インタプリタを噛ませると前提が崩れる。
検証方法
メタ文字を含む URL(https://example.com/?a=1&calc)を起動関数に渡し、追加のプロセスが起動しないこと・拒否されることを Windows で確認する。
MCP/ツールのレスポンスに外部由来データを埋め込む時はプロンプトインジェクションを区切る
約6時間前
問題
MCP サーバーやエージェントのツールが、API から取得したデータ(メモ本文、著者名、公開コンテンツ等)を区切りなくそのままツール結果テキストに連結して返すと、その中に「これまでの指示を無視して…」のような文言が含まれていた場合、呼び出し側 LLM への間接プロンプトインジェクション経路になる。とくに公開メモ・いいね・コメントなど他ユーザー由来のコンテンツを返す経路はリスクが高い。ツール定義の description は静的なら問題ないが、レスポンス本文は外部入力で動的に変わる点が見落とされやすい。
判断基準
- ツール結果に外部由来データを載せるときは、それが「データであって指示ではない」ことを明示する区切り(フェンスや注記)で囲む。
- とくに他ユーザー・第三者が編集できるコンテンツを返す経路では必須とみなす。自分専用データのみを返す経路でも、内容に他者由来テキストが混ざりうるなら同様に扱う。
- 認可スコープでの多層防御も併用する。注入があってもツールがリクエスト者の
userIDでしかデータ取得できなければ、越境アクセス自体は防げる。
検証観点
注入文言を含むコンテンツを保存し、それをツールが返したとき、出力上でユーザーデータと指示が明確に分離されているかを確認する。区切りがない場合、下流 LLM が埋め込み指示に従う挙動を再現テストする。
react-markdownはデフォルトで危険URLと生HTMLを無害化する(XSS誤検知の判別)
約10時間前
仕様
react-markdown は v9 以降、リンクや画像の URL を既定の urlTransform(defaultUrlTransform)で検証し、javascript: data: などの危険スキームを取り除く。許可されるのは http / https / mailto / tel と相対 URL 程度。さらに生の HTML(<script> や <iframe> など)はデフォルトでは一切レンダリングされない。
そのため、ユーザー入力の Markdown を素の react-markdown で表示しているだけなら、javascript: リンク注入や HTML 埋め込みによる XSS は既定で防がれている。
監査時の判断基準
Markdown レンダリングを XSS として指摘する前に、次を確認する。これらが無ければ多くは誤検知。
rehype-rawを使っていないか(使うと生 HTML がそのまま描画され、別途サニタイズが必須になる)。urlTransform/transformLinkUriを独自実装で上書きし、無害化を外していないか。dangerouslySetInnerHTMLで別経路にレンダリングしていないか。
アプリ側コードに href?.startsWith('http') のようなスキーム判定ロジックがあっても、それは target=_blank 付与など表示制御目的であることが多く、サニタイズ責務はライブラリ側にある。判定ロジックのバグ(例: || のつもりで ?? を使う)は論理バグではあっても、URL 無害化が効いていれば XSS にはならない。
検証方法
[x](javascript:alert(1)) や生 <img onerror=...> を含む Markdown を実際に描画し、生成 DOM の href / 要素を確認する。href が除去・置換され、HTML がエスケープされていれば既定の保護が効いている。保護を意図的に外す(rehype-raw 導入など)場合のみ、DOMPurify 等での明示的サニタイズを必須とする。
クラウドストレージの削除APIはプレフィックス制限と所有者検証を必須にする
約6時間前
問題
オブジェクトストレージ(GCS/S3 等)の削除エンドポイントで、クライアントが送ってきたオブジェクト URL を正規表現などでパース対象キーに変換し、認証だけ通っていれば削除する実装は危険。https://storage.example.com/<bucket>/(.+) のように (.+) で任意パスを拾うと、他ユーザーの URL(公開プロフィール等から取得可能)を投げるだけでそのオブジェクトを削除でき、バケット内の任意オブジェクトに波及しうる(IDOR / Broken Access Control)。アップロード側は profiles/ などにプレフィックス制限しているのに、削除側だけ制限が抜けるパターンが典型。
判断基準
- 認証(誰がログインしているか)と認可(そのオブジェクトが本人のものか)は別物。削除経路では必ず所有者検証を入れる。
- 対策の柱は二つ。(1) 削除可能なキーを所定プレフィックスに限定する。(2) ファイル名やパスにユーザー識別子を含め、リクエスト者と一致するキーだけ削除許可する。あるいは所有権判定を持つバックエンド側に削除を委譲する。
- 存在/非存在でレスポンス差分を返すと、オブジェクト列挙(存在確認)にも悪用されるため、所有者検証を入れて経路ごと塞ぐ。
検証方法
ユーザーA でログインし、ユーザーB のオブジェクト URL や所定プレフィックス外のキーを指定して削除 API を呼ぶ。所有者・プレフィックス検証があれば対象は削除されず拒否されることを確認する。アップロード経路にプレフィックス制限があっても削除経路は別実装になりやすいので個別にテストする。
一括更新・並び替えAPIは所有者チェックが漏れやすい(IDOR検査観点)
約10時間前
問題
リソースの単体 Update / Delete には所有者チェック(WHERE id = ? AND user_id = ? 相当)があるのに、並び替えや一括更新のエンドポイントだけ抜けていることが多い。とくに CTE や VALUES を使った一括 UPDATE で WHERE 対象.id = 入力.id のように ID だけで突き合わせ、所有者条件を付け忘れると、認証済みの任意ユーザーが他人のリソースを書き換えられる(IDOR / Broken Access Control)。
影響が並び順や軽微なフィールドの改ざんに留まっても、テナント越えの書き込みであることに変わりはない。
判断基準
- 「読み取りはスコープしているか」だけでなく「すべての書き込み経路がスコープしているか」を観点にする。とくに bulk/sort/move/reorder/batch 系は単体操作とは別実装になりがちなので個別に確認する。
- 入力 ID 群が本当に当該ユーザーのものかを検証するか、UPDATE/DELETE の WHERE に常に所有者条件を含める。アプリ層の事前チェックだけに頼らず、データアクセス層のクエリ自体にも条件を残すと安全。
検証方法
ユーザーA でログインし、ユーザーB のリソース ID を指定して並び替え・一括更新を呼ぶ。所有者条件があれば B のレコードは変化せず、A の所有外 ID は更新対象にならないことを確認する。単体操作のテストが通っていても bulk 系は別途テストする。