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
服务器端请求伪造:不可信输入促使软件从自身网络位置发出请求。[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]

源代码对比:漏洞与安全实现

这些代码片段来自官方 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}]")

工程与系统安全加固清单

参考来源