
Untrusted upstream:プロバイダーが、応答に入っていたURLをそのまま開いた話。
Drupal OpenAI Provider(ai_provider_openai)・SSRF(CWE-918)・CVE-2026-13233・SA-CONTRIB-2026-053
状態:協調的開示は 完了(2026-07-10)。Drupal Security Team へ非公開で報告 → 修正 → CVE-2026-13233/ アドバイザリ SA-CONTRIB-2026-053(格付け Moderately critical)として公開。著者は finder かつ remediation developer としてクレジット。
AIの「接続部分」に古典的な認可/入力検証の欠陥が出た事例の研究。あるAI画像生成プロバイダーが、
上流APIの応答に含まれるURLを、汎用の取得関数でスキーム検査なしに取得していた。接続先(host)が
既定の正規APIではない配備(自前エンドポイント/プロキシ/自己ホストのゲートウェイ/侵害された中継)では、
上流が応答URLとして file:// や内部アドレスを返すことで、サーバーがそれを開いた。
sink に届く未信頼入力は、利用者のプロンプトではなく上流の応答URLである。
file:// によるローカルファイル読み取りが含まれる
(著者の内部分析では CWE-73/CWE-441 にも対応づけ)。3.1/条件付き 5.3(Medium)で、旧 6.5・7.4 の撤回とも整合。ai_provider_openai)< 1.1.1 および 1.2.0〜1.2.1(監査 1.2.1)/ Drupal core 11.2検証はすべて、自分が所有・管理するネットワーク隔離サンドボックスで、モック上流に対して実施した。 実 OpenAI API は一度も呼んでいない。漏えいオラクルは合成データのみ。
確認済み(動的に実証):
settings.php(35,182 B)を sha256 バイト一致で確認(中身は非出力)。DB 資格情報が射程内という意味。未検証(主張しない):
非該当:既定の api.openai.com(TLS)。host は管理者/config-sync/デプロイ側の管理下で、実行時の非管理者攻撃者は変更不可。
応答URLを、登録済みのあらゆる PHP ストリームラッパー(file, php, http, data, phar …)を解釈する汎用取得へ
渡していた。response_format の既定は url なので、この脆弱な分岐が既定経路。file:// は PHP の既定の
ファイルシステム wrapper で、allow_url_fopen の対象外(「allow_url_fopen が前提」という旧記述は誤りで撤回)。
プリミティブを直す(call-site だけ直さない):
http/https に限定し、リダイレクトを無効化(30x が file:// へ跳ぶのを防ぐ)。file://…・http://169.254.169.254/…・302→file:// を全て拒否。英語版 README.md の "Directory structure" と同一。要点:docs/(記事A/B/C は現在日本語 *.ja.md・英訳はTODO、
+ fix-direction.md は英語)、reproducer/(安全化再現・モック上流・単一の無害オラクル /etc/hostname のみ)、
detections/(Sigma×2 / Sentinel KQL / Splunk SPL の実ファイル)、SECURITY.md、timeline.md(開示タイムライン正本)、
.gitignore(秘密値・一次証跡の混入防止)。
本リポジトリに含めないもの:arming ペイロード、動作するファイル読取PoC、秘密値を含む一次証跡。 公開
reproducer/は単一の無害オラクル/etc/hostnameで欠陥クラスの機構をモックに対して示すのみ。 任意パス読取・settings.php取得・IMDS は入れない。稼働サイトへの武器ではない。まず 1.1.1 / 1.2.2 へ更新を。
目的:稼働環境への攻撃手順や秘密値を出さずに、研究者が欠陥クラスを確認できるようにする。すべてオフライン。
docker compose(言語プリミティブ検査は --network none)。
資格情報は mount しない。モックは実APIと通信しない。host が未信頼プロキシ/自己ホストゲートウェイを指す」状況を演じる。
標的URLはプロンプト経由ではなく out-of-band で armする=訂正後の攻撃者モデル(URLは上流が決め、利用者は起動のみ)。file:///etc/hostname+アプリコンテナ内にのみ作る per-run マーカー(上流が選んだ任意パスの証明)、
settings.php は sha256 一致のみ・中身非出力、公開ポート無しの内部HTTPサービス(合成トークン)。0/1/2/3/99)。reproducer/verdict.md 参照。timeline.md が正本。要約は英語版 README の表と同一(静的発見→動的実証→ピアレビューでHOLD→
セキュリティチーム報告→修正版+Advisory 公開で public 化→CVE/JVN・クレジット、の順。日付の一部は保留)。
実ルールは detections/、背景は docs/detection-engineering.md。要点:
169.254.169.254/loopback/RFC1918 への異常 egress
(プロキシ/EDR)を、狭い時間窓で相関する。egress 単独ではアラートにしない。file:// はネットワークに出ない。Webプロセスによる機微ファイルの open をホスト監査で拾う(ベースライン化し、
画像生成と同一リクエストの off-pattern read に絞る)。image/* を名乗る非画像バイト(先頭マジックバイト不一致)を後追いで洗う。{request_id, actor, target_url, scheme, resolved_ip, content_type} の fetch 監査を足す。標準ログだけでは検知できない。file:// は既定 wrapper・allow_url_fopen 対象外)reproducer/ はサンドボックス専用・合成オラクルで、稼働環境への攻撃ではなく、秘密値も含まない。
所有・許可のない環境で実行しないこと。本研究はすべて、著者が所有するネットワーク隔離サンドボックスで、モック上流に対して実施した。実ベンダーAPIには
一切接続しておらず、第三者環境は一度も検証していない。 発見はまず Drupal Security Team へ非公開で報告し、公開は
修正版とアドバイザリ(SA-CONTRIB-2026-053・CVE-2026-13233)の公開に同期した。ベンダー格付けは Moderately critical。
CVSS は著者の暫定的な自己評価であって公式スコアではなく、意図的に保守側に置いた(CVSS の Critical/High としない)
——これはベンダーの中位帯格付けとも整合する。本資料は防御・教育目的。詳細は SECURITY.md。