
PoC for CVE-2026-18953 — awslabs.aws-transform-mcp-server의 get_resource 도구에서 savePath 매개변수를 통한 임의 파일 쓰기(CWE-22) 취약점
| 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()는 다음만 수행합니다:
save_path를 os.path.realpath(os.path.expanduser(...))로 해석합니다.~/.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 클라이언트 — 동일한 도구를 통해 가져오는 신뢰할 수 없는 job/task/message 콘텐츠로 간접적으로 프롬프트 인젝션(prompt injection)된 에이전트를 포함 — 는 savePath를 절대 경로, ../.. 경로 탐색, 또는 민감한 dotfile 이름으로 설정할 수 있으며, 서버는 공격자가 조작한 바이트를 해당 위치에 기록합니다. 이는 운영자가 다운로드가 제한된다고 믿는 디렉터리 밖으로의 파일 쓰기 프리미티브(file-write primitive)입니다. 보안 권고는 "로컬 코드 실행으로 이어질 수 있다"고 명시합니다(예: 셸 시작 파일 덮어쓰기).
0.1.5는 모든 해석된 쓰기 경로가 반드시 그 아래에 위치해야 하는 명시적 허용 목록(allow-list) 기본 디렉터리(_ALLOWED_WRITE_BASE, 시작 시 $AWS_TRANSFORM_MCP_WRITE_DIR 또는 서버의 CWD에서 가져옴)를 추가하고, 최종 해석된 쓰기 경로에 대해서도 BLOCKED_FILENAMES를 적용하여 이 문제를 수정합니다.
근본 원인 전체 diff: vendor/0.1.4-vulnerable/file_validation.py vs. 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" 콘텐츠는 채팅/job 데이터에서 비롯되므로, 작업공간 협업자(또는 손상된 업스트림 job/message 소스)는 사람에게 이 내용을 직접 입력하도록 설득할 필요가 없습니다. 이미 연결된 에이전트를 악성 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 쌍 — 절대 경로 탈출, 상대 경로 ../.. 탐색, 읽기에서만 차단되는 dotfile 이름 — 을 실행합니다.모든 작업은 폐기 가능한 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로 업그레이드하세요. 이전 버전에는 서버 측 해결 방법(workaround)이 없으며, 보안 권고는 업그레이드를 권장합니다. 즉시 업그레이드할 수 없는 운영자는 서버의 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