FlawOpen

flawopen.com/Teardowns/cve-2026-106032-bedrock-agentcore-openapi-reference-ssrf

● CVE-2026-106032 · CVSS v4 5.7 · 中
セキュリティ研究 · FlawOpen

CVE-2026-106032:AgentCore OpenAPI インポーターの SSRF

Starter Toolkit 0.3.13 以前は、エージェントのインポート時に外部 OpenAPI 参照を解決していました。細工されたアクショングループのデータにより、外向きリクエストやローカルファイルの読み取りが起きる可能性があります。0.3.14 以降へ更新し、対象エージェントを再インポートして生成物を置き換えてください。[1], [2], [3]

💡 わかりやすい解説 (ELI5)

インポーターを、文書の参照先をたどって書類をまとめる担当者だと考えてください。脆弱な担当者は、書類の外やローカルファイルを指す参照にも従っていました。そのため、一見信頼できるエージェントが、作業中の端末にデータの取得や読み取りをさせる可能性がありました。修正では同じ文書内の参照だけを許可します。[2], [7], [8]

主要な概念と専門用語

OpenAPI $ref
OpenAPI のスキーマや定義を指す参照です。フラグメント参照は現在の文書内を指し、外部参照は別のリソースを指す場合があります。[1]
Prance ResolvingParser
Starter Toolkit がエージェントのインポート時に OpenAPI 参照を読み込み、解決するパーサーです。[2]
SSRF
Server-side request forgery。不可信な入力により、ソフトウェア自身のネットワーク位置からリクエストが送信される問題です。[7], [8]
CWE-918
CVE レコードの構造化された主 cweId は CWE-918(Server-Side Request Forgery)です。説明には、ファイルパスが外部から制御される側面を示す CWE-73 も記載されています。[2], [3], [5]
CWE-73: External Control of File Name or Path
同じ CVE レコードは、ローカルファイル読み取りの側面について CWE-73(ファイル名またはパスの外部制御)も挙げています。CWE-73 は問題種別の説明に記載され、構造化された主 cweId は CWE-918 です。[3], [9]

フレームワーク対応

根本原因の分析 (Root Cause)

0.3.13 では get_agent_info() がアクショングループの OpenAPI データを prance.ResolvingParser に直接渡し、参照解決の種類を制限していませんでした。0.3.14 ではパーサーの前に assert_local_references_only() を呼び、内部フラグメント接頭辞 #/ で始まらない文字列の $ref を再帰的に拒否し、さらに resolve_types=RESOLVE_INTERNAL を指定します。これにより、このインポート経路でパーサーが外部 OpenAPI 参照を取得するのを防ぎます。保守元のテストはパーサー呼び出し前の拒否を確認し、HTTP、file、絶対パス、ネットワークパスを検証する一方、文書内フラグメントは許可します。この結果を別のインポート経路に一般化したり、プロセスのすべてのネットワーク・ファイルアクセスを防ぐと解釈したりしないでください。正式な対処は更新です。コード比較は上流の境界を示すもので、悪用手順ではありません。 GitHubのアドバイザリは@seankohjsを報告者として記載し、AWSは脆弱性の協調的な開示への協力についてKoh Jun Shengに謝意を示しています。[2], [7], [8], [1]

ステップ・バイ・ステップの攻撃フロー

ステップ 1

同一アカウントの主体がエージェントデータを変更

同じ AWS アカウントの認証済み主体が Bedrock Agent のアクショングループ OpenAPI スキーマを変更し、細工された外部参照値を配置できる必要があります。これは未認証のインターネット攻撃ではありません。[2]

ステップ 2

別のユーザーがエージェントをインポート

ユーザーが影響を受ける Starter Toolkit のインポート処理を実行します。脆弱なバージョンはこの処理でアクショングループの OpenAPI を解析します。[1], [2]

ステップ 3

パーサーが外部参照を解決

0.3.13 は内部参照に限定せず文書を ResolvingParser に渡していました。細工された外部参照により、インポート環境から外向きリクエストやローカルファイルへのアクセスが起こる可能性があります。[7], [2]

ステップ 4

更新し、再インポートして成果物を置換

0.3.14 以降へ更新し、影響バージョンでインポートしたエージェントを再インポートして、ローカルとデプロイ済みの成果物を置き換えます。可能であれば非推奨の Starter Toolkit から @aws/agentcore に移行してください。[1], [8]

ソースコード比較:脆弱 vs 堅牢化

コード抜粋は公式の 0.3.13 と 0.3.14 のソース配布物から取得しました。修正は Prance の実行前に外部 $ref を拒否し、解決対象を内部参照に制限します。上流テストはパーサー前の拒否と内部フラグメントの許可を確認します。これは焦点を絞ったソース比較であり、リクエスト例ではありません。抜粋を転用せず、パッケージを更新してください。[7], [8], [2]

ソース抜粋: AgentCore インポーター 0.3.13 と 0.3.14 の抜粋

脆弱な実装
# 0.3.13: パーサーが OpenAPI 文書の参照を解決する。
parser = ResolvingParser(
    spec_string=json.dumps(action_group["apiSchema"]["payload"])
)
action_group["apiSchema"]["payload"] = parser.specification
堅牢化されたセキュアパッチ
# 0.3.14: 解析前に外部参照を拒否する。
assert_local_references_only(action_group["apiSchema"]["payload"])
parser = ResolvingParser(
    spec_string=json.dumps(action_group["apiSchema"]["payload"]),
    resolve_types=RESOLVE_INTERNAL,
)

def assert_local_references_only(node, path: str = "$") -> None:
    if isinstance(node, dict):
        reference = node.get("$ref")
        if isinstance(reference, str) and not reference.startswith("#/"):
            raise ValueError(
                f"External OpenAPI references are not supported: {reference!r} at {path}."
            )
        for key, child in node.items():
            assert_local_references_only(child, f"{path}.{key}")
    elif isinstance(node, list):
        for index, child in enumerate(node):
            assert_local_references_only(child, f"{path}[{index}]")

エンジニアリング&システム堅牢化チェックリスト

参考資料