
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.
docker compose com o app e um upstream mock em uma rede isolada (--network none
para as verificações de primitivas da linguagem). Nenhuma credencial montada. O mock nunca fala com a API real.host apontando para um proxy/gateway
auto-hospedado não confiável". Ele é armado fora de banda (não via prompt) para retornar uma URL alvo sintética — isso codifica
o modelo de atacante corrigido (o upstream escolhe a URL, o usuário apenas dispara).file:///etc/hostname e um marcador único por execução gravado apenas dentro do contêiner do app → prova
que o app leu um caminho escolhido pelo upstream (marcador ausente no mock).settings.php verificado por byte-match sha256, conteúdo nunca emitido → prova "credenciais de banco em escopo"
sem divulgá-las.0 explorável / 1 pré-condição /
2 não reproduzido / 3 falha na limpeza / 99 erro). Veja reproducer/verdict.md.Veja reproducer/README.md.
Veja timeline.md. Resumo:
| Data | Evento |
|---|---|
| 2026-06-10 | Revisão estática localiza o sink; leitura file:// de caminho fixo confirmada dinamicamente |
| 2026-06-11 | Leitura de caminho arbitrário + byte-match sha256 de settings.php + SSRF HTTP interna confirmados |
| 2026-06-11 | Alcance de consumidores de produção (automator por caminho interno; exfiltração HTTP legítima via FWA) |
| 2026-06/07 | Itens de HOLD resolvidos; reportado em privado à Equipe de Segurança do Drupal; gêmeo na classe base sinalizado para drupal/ai |
| 2026-07-10 | Versões corrigidas 1.1.1 / 1.2.2; advisory SA-CONTRIB-2026-053 e CVE-2026-13233 publicados; autor creditado como descobridor e desenvolvedor da correção |
As detecções para profissionais estão em detections/; a fundamentação em
docs/detection-engineering.md. Em resumo:
169.254.169.254 / loopback / RFC1918 em uma janela de tempo curta após a chamada à API. Não alerte apenas por
egress.file:// nunca passam pela rede — detecte aberturas de arquivos sensíveis por processos web via auditoria de host
(auditd/EDR), com baseline para que apenas leituras fora do padrão dentro de uma requisição de geração de imagem disparem.image/* cujos magic bytes não são uma imagem.{request_id, actor, target_url, scheme, resolved_ip, content_type}. Apenas logs padrão não vão capturar isso.file:// é o stream wrapper de filesystem padrão; não controlado por allow_url_fopen)reproducer/ é apenas para sandbox e usa oráculos sintéticos. Não é um exploit para alvo ativo e
não contém segredos. Não o execute contra sistemas que você não possui e para os quais não está autorizado a testar.Toda a pesquisa foi realizada pelo autor em um sandbox próprio, isolado de rede, contra um upstream mock —
a API real do fornecedor nunca foi contatada, e nenhum sistema de terceiros foi testado. A descoberta foi reportada
primeiro em privado à Equipe de Segurança do Drupal e publicada apenas em sincronia com a correção e o advisory
(SA-CONTRIB-2026-053, CVE-2026-13233); a classificação do fornecedor é Moderadamente crítico. Os valores CVSS do autor
são uma autoavaliação provisória, não uma pontuação oficial, e foram deliberadamente mantidos conservadores (sem
CVSS Crítico/Alto) — consistentes com a classificação de faixa média do fornecedor. Este material tem fins defensivos e
educacionais. Veja SECURITY.md.