テナントのサブドメインを URL に組み込む前に許可リストで照合する(SAP Cloud SDK for Python の CVSS 10.0)
マルチテナントのアプリが「テナントを表すサブドメイン」を外部入力から受け取り、OAuth のトークン取得 URL に埋め込むと、攻撃者は宛先を自分のサーバーに変えてクライアント ID とシークレットを受け取れる。URL を組み立てる前に、登録済みサブドメインの許可リストと照合する。
何が問題だったか
- SAP Cloud SDK for Python は、テナントのサブドメインを OAuth2 トークン取得用 URL に組み込み、その宛先にアプリのクライアント ID とシークレットを送っていた。
- サブドメインを検証しないため、URL の区切り文字などを含む値を渡されると宛先が攻撃者のサーバーに変わる SSRF になる(CVE-2026-89111、CVSS 3.1 で 10.0)。
- 公式の影響版は 0.45.2 未満で、修正版は 0.45.2。ただし修正版より後に公開された 0.36.1・0.36.2 も影響範囲内。さらに The Hacker News の独自検証では、Destination 連携の 0.53.0〜0.55.0(6 版)と Document Management Service 連携の 0.55.0 にも検証の欠落があった。
- 0.55.1 で共通の認証処理にサブドメイン検証が追加され、区切り文字を含む値はエラーで拒否されるようになった(この 6 版が同じ CVE に含まれるかは公式には書かれていない)。
対策
- SDK を 0.55.1 以降にする。 「修正版の番号以上なら安全」と思わず、後続の版の修正内容まで確認する。
- アプリ側でも、SDK に渡す前にサブドメインを登録済みの許可リストと照合する(SAP が示す回避策)。SDK の修正に頼り切らない二重の防御になる。
- 自前で同じ処理を書くときの原則:
- テナント識別子はリクエストのヘッダーやパラメーターから直接取らず、認証済みのセッションやテナント登録情報から引く。
- 文字種を
^[a-z0-9-]{1,63}$のように制限し、./@?#:を含む値は拒否する。 - URL は文字列連結ではなく URL パーサーで組み立て、完成後のホスト名が想定ドメイン配下かを確認してから送信する。
- シークレットを送る通信の宛先は固定にし、外部入力で変わらない構成にする。