
CVE-2026-13233 (Drupal OpenAI Provider, SA-CONTRIB-2026-053): SSRF de response-URL / lectura de archivos locales. Upstream no confiable, no el prompt. Reproductor seguro + detecciones. Corregido en 1.1.1/1.2.2.
Upstream no confiable: el proveedor que descargó la URL que su propia respuesta le indicaba.
Drupal OpenAI Provider (ai_provider_openai) · SSRF (CWE-918) · CVE-2026-13233 · SA-CONTRIB-2026-053
Estado: Divulgación coordinada completa (2026-07-10). Notificado de forma privada al equipo de seguridad de Drupal, corregido y publicado como CVE-2026-13233 / aviso SA-CONTRIB-2026-053 (calificado como Moderadamente crítico). El autor figura como descubridor y desarrollador de la corrección.
Un estudio de un defecto clásico de autorización / validación de entrada en un "punto de conexión" de IA: un
proveedor de generación de imágenes por IA descargaba la URL contenida en la respuesta de la API upstream mediante una
función de propósito general sin lista blanca de esquemas. En despliegues donde el upstream configurado
no es el predeterminado de confianza (trae-tu-propio-endpoint / proxy / gateway auto-alojado / relay
comprometido), la respuesta podía apuntar el servidor a file:// o a una dirección interna.
La entrada no confiable que llega al sumidero (sink) es la URL de la respuesta del upstream — no el prompt del usuario.
file://; el
análisis interno del autor también lo asignó a CWE-73 / CWE-441.3.1 / condicional 5.3
(Medium); los anteriores 6.5 / 7.4 retractados, y la calificación media lo confirmó.ai_provider_openai) < 1.1.1 y 1.2.0–1.2.1 (auditado 1.2.1) en Drupal core 11.2Toda la verificación se ejecutó en un sandbox propio, aislado de la red, contra un upstream simulado (mock). La API real de OpenAI nunca se llamó. Los oráculos de fuga eran solo sintéticos.
Confirmado (demostrado dinámicamente):
settings.php confirmada por coincidencia de bytes sha256 (35,182 B) — el contenido nunca se imprimió; por lo tanto,
las credenciales de la base de datos están dentro del alcance.No verificado (explícitamente no reclamado):
No afectado: api.openai.com predeterminado sobre TLS. El ajuste host está controlado por el administrador / config-sync / despliegue
— un atacante no administrador en tiempo de ejecución no puede cambiarlo.
La URL de la respuesta se pasaba a una descarga de propósito general que respeta todos los wrappers de flujo de PHP
registrados (file, php, http, data, phar, …). response_format tiene como valor predeterminado url, por lo que la rama
vulnerable es la ruta predeterminada. file:// es el wrapper de sistema de archivos predeterminado de PHP y no está controlado por
allow_url_fopen (una afirmación anterior de "requiere allow_url_fopen" era incorrecta y queda retractada).
Corrija la primitiva, no solo el punto de llamada:
http/https antes de la solicitud; deshabilite las redirecciones (un 30x puede rebotar a file://).file://…, http://169.254.169.254/…, y una
redirección 302→file:// deben ser rechazadas.Dirección completa: docs/fix-direction.md.
.
├── README.md # this file (English, canonical)
├── README_ja.md # Japanese mirror
├── SECURITY.md # reporting policy + responsible-disclosure disclaimer
├── .gitignore # blocks secrets / primary evidence from being committed
├── docs/
│ └── fix-direction.md # root-cause fix + variant hunt + minimal-diff sketch (EN)
├── reproducer/ # SAFE reproducer only (sandbox, mock upstream, benign oracle)
│ ├── README.md # how to stand up the network-isolated sandbox
│ ├── verdict.md # what "success" means: raw-byte match + 200-vs-403 + exit codes
│ ├── mock-openai-server.py # benign mock; default happy-path PNG, ssrf_demo → file:///etc/hostname only
│ └── docker-compose.yml # TEMPLATE: isolated Drupal sandbox + mock (you add the vulnerable target)
├── 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 # disclosure timeline (single source of truth)
La documentación está actualmente en japonés (
.ja.md); las traducciones canónicas al inglés son un TODO. Retenido de este repositorio: payloads de armado y cualquier PoC de lectura de archivos llave en mano. Elreproducer/público demuestra el mecanismo del defecto contra un mock usando un único oráculo benigno (/etc/hostname) — sin lectura de ruta arbitraria, sin captura desettings.php, sin IMDS. No es un arma contra sitios en producción. Actualice a 1.1.1 / 1.2.2.
Objetivo: permitir que un investigador confirme la clase del defecto sin proporcionar un exploit para objetivos en producción ni exponer secretos. Todo se ejecuta sin conexión.
docker compose con la aplicación y un upstream mock en una red aislada (--network none
para las comprobaciones de primitivas del lenguaje). No se montan credenciales. El mock nunca habla con la API real.host que apunta a un proxy/gateway auto-alojado
no confiable". Se arma fuera de banda (no a través del prompt) para devolver una URL objetivo sintética — esto codifica
el modelo de atacante corregido (el upstream elige la URL, el usuario solo dispara).file:///etc/hostname y un marcador único por ejecución escrito solo dentro del contenedor de la aplicación → demuestra
que la aplicación leyó una ruta elegida por el upstream (el marcador está ausente en el mock).settings.php verificado por coincidencia de bytes sha256, el contenido nunca se emite → demuestra "credenciales de BD dentro del alcance"
sin divulgarlas.0 explotable / 1 condición previa /
no reproducido / fallo de limpieza / error). Ver .Ver reproducer/README.md.
Ver timeline.md. Resumen:
Las detecciones para profesionales están en detections/; el fundamento en
docs/detection-engineering.md. En resumen:
169.254.169.254 / loopback / RFC1918 en una ventana de tiempo estrecha después de la llamada a la API. No alerte solo por
el egreso.file:// nunca tocan la red — detecte aperturas de archivos sensibles por procesos web mediante auditoría de host
(auditd/EDR), con línea base para que solo se activen las lecturas fuera de patrón dentro de una solicitud de generación de imágenes.image/* cuyos bytes mágicos no son una imagen.{request_id, actor, target_url, scheme, resolved_ip, content_type}. Los registros estándar por sí solos no detectarán esto.file:// es el wrapper de sistema de archivos predeterminado; no está controlado por allow_url_fopen)reproducer/ es solo para sandbox y usa oráculos sintéticos. No es un exploit para objetivos en producción y
no contiene secretos. No lo ejecute contra sistemas que no posea y para los que no esté autorizado a probar.Toda la investigación fue realizada por el autor en un sandbox propio, aislado de la red, contra un upstream mock —
la API real del proveedor nunca fue contactada y ningún sistema de terceros fue probado. El hallazgo se notificó
de forma privada primero al equipo de seguridad de Drupal y se publicó solo en sincronía con la corrección y el aviso
(SA-CONTRIB-2026-053, CVE-2026-13233); la calificación del proveedor es Moderadamente crítico. Las cifras CVSS del autor
son una autoevaluación provisional, no una puntuación oficial, y se mantuvieron deliberadamente conservadoras (sin
CVSS Critical/High) — coherentes con la banda media del proveedor. Este material tiene fines defensivos y
educativos. Ver SECURITY.md.
2399| Fecha | Evento |
|---|
| 2026-06-10 | La revisión estática localiza el sumidero; lectura de ruta fija file:// confirmada dinámicamente |
| 2026-06-11 | Lectura de ruta arbitraria + coincidencia sha256 de settings.php + SSRF HTTP interno confirmados |
| 2026-06-11 | Alcance en consumidores de producción (ruta interna del automatizador; exfiltración HTTP legítima de FWA) |
| 2026-06-11 | Revisión independiente por pares corrige afirmaciones exageradas (modelo de atacante, CVSS, allow_url_fopen); el envío se pone en HOLD |
| 2026-06/07 | Elementos de HOLD resueltos; notificado de forma privada al equipo de seguridad de Drupal; el gemelo de la clase base se señala a drupal/ai |
| 2026-07-10 | Versiones corregidas 1.1.1 / 1.2.2; aviso SA-CONTRIB-2026-053 y CVE-2026-13233 publicados; el autor figura como descubridor y desarrollador de la corrección |