
CVE-2026-13233 (Drupal OpenAI Provider, SA-CONTRIB-2026-053): SSRF via URL de resposta / leitura de arquivo local. Upstream não confiável, não o prompt. Reprodução segura + detecções. Corrigido em 1.1.1/1.2.2.
Upstream não confiável: o provedor buscava a URL indicada pela resposta do upstream.
Drupal OpenAI Provider (ai_provider_openai) · SSRF (CWE-918) · CVE-2026-13233 · SA-CONTRIB-2026-053
Status: Divulgação coordenada concluída (2026-07-10). Reportado em privado à Equipe de Segurança do Drupal, corrigido e publicado como CVE-2026-13233 / advisory SA-CONTRIB-2026-053 (avaliado como Moderadamente crítico). Autor creditado como descobridor e desenvolvedor da correção.
Um estudo de um defeito clássico de autorização / validação de entrada em um "ponto de conexão" de IA: um
provedor de geração de imagens por IA buscava a URL contida na resposta da API upstream usando uma
função de propósito geral sem allowlist de esquema. Em implantações onde o upstream configurado
não é o padrão confiável (bring-your-own-endpoint / proxy / gateway auto-hospedado / relay
comprometido), a resposta poderia apontar o servidor para file:// ou um endereço interno.
A entrada não confiável que chega ao sink é a URL da resposta do upstream — não o prompt do usuário.
file://; a análise
interna do autor também a mapeou para CWE-73 / CWE-441.3.1 / condicional 5.3
(Médio); pontuações anteriores 6.5 / 7.4 retratadas, e a classificação média confirmou isso.ai_provider_openai) < 1.1.1 e 1.2.0–1.2.1 (auditado 1.2.1) no Drupal core 11.2Toda a verificação foi executada em um sandbox próprio, isolado de rede, contra um upstream mock. A API real da OpenAI nunca foi chamada. Os oráculos de vazamento foram apenas sintéticos.
Confirmado (demonstrado dinamicamente):
settings.php confirmada por byte-match sha256 (35.182 B) — conteúdo nunca impresso; credenciais de
banco de dados estão, portanto, em escopo.Não verificado (explicitamente não reivindicado):
Não afetado: o api.openai.com padrão via TLS. A configuração host é controlada por admin / config-sync / deploy
— um atacante não-admin em tempo de execução não pode alterá-la.
A URL da resposta era passada para um fetch de propósito geral que honra todos os stream wrappers registrados
no PHP (file, php, http, data, phar, …). response_format tem como padrão url, então o branch
vulnerável é o caminho padrão. file:// é o stream wrapper de filesystem padrão do PHP e não é controlado por
allow_url_fopen (uma afirmação anterior de que "exige allow_url_fopen" estava errada e foi retratada).
Corrija a primitiva, não apenas o ponto de chamada:
http/https antes da requisição; desabilite redirecionamentos (um 30x pode saltar para file://).file://…, http://169.254.169.254/… e um
redirecionamento 302→file:// devem ser todos recusados.Direção completa: docs/fix-direction.md.
.
├── README.md # este arquivo (inglês, canônico)
├── README_ja.md # espelho em japonês
├── SECURITY.md # política de reporte + aviso de divulgação responsável
├── .gitignore # impede que segredos / evidências primárias sejam commitados
├── docs/
│ └── fix-direction.md # correção da causa-raiz + caça a variantes + esboço de diff mínimo (EN)
├── reproducer/ # apenas reprodutor SEGURO (sandbox, upstream mock, oráculo benigno)
│ ├── README.md # como montar o sandbox isolado de rede
│ ├── verdict.md # o que "sucesso" significa: byte-match + 200-vs-403 + códigos de saída
│ ├── mock-openai-server.py # mock benigno; PNG de happy-path padrão, ssrf_demo → apenas file:///etc/hostname
│ └── docker-compose.yml # MODELO: sandbox Drupal isolado + mock (você adiciona o alvo vulnerável)
├── detections/
│ ├── README.md
│ ├── sigma/web-egress-to-internal-after-imagegen.yml
│ ├── sigma/php-sensitive-file-open.yml
│ ├── sentinel/imagegen-egress-correlation.kql
│ └── splunk/imagegen-content-type-mismatch.spl
└── timeline.md # linha do tempo da divulgação (fonte única da verdade)
A documentação está atualmente em japonês (
.ja.md); traduções canônicas em inglês são um TODO. Retido deste repositório: payloads de armamento e qualquer PoC turnkey de leitura de arquivos. Oreproducer/público demonstra o mecanismo do defeito contra um mock usando um único oráculo benigno (/etc/hostname) — sem leitura de caminho arbitrário, sem captura desettings.php, sem IMDS. Não é uma arma contra sites ativos. Atualize para 1.1.1 / 1.2.2.
Objetivo: permitir que um pesquisador confirme a classe do defeito sem fornecer um exploit para alvo ativo ou expor segredos. Tudo roda offline.