
CVE-2026-13233 (Drupal OpenAI Provider, SA-CONTRIB-2026-053): SSRF über Antwort-URL / lokales Dateilesen. Nicht vertrauenswürdiger Upstream, nicht der Prompt. Sicherer Reproducer + Erkennungen. Behoben in 1.1.1/1.2.2.
Nicht vertrauenswürdiger Upstream: der Provider, der die URL abgerufen hat, die seine Antwort ihm vorgab.
Drupal OpenAI Provider (ai_provider_openai) · SSRF (CWE-918) · CVE-2026-13233 · SA-CONTRIB-2026-053
Status: Koordinierte Offenlegung abgeschlossen (2026-07-10). Privat an das Drupal-Sicherheitsteam gemeldet, behoben und als CVE-2026-13233 / Advisory SA-CONTRIB-2026-053 veröffentlicht (bewertet als Mäßig kritisch). Autor als Finder & Entwickler der Behebung genannt.
Eine Untersuchung eines klassischen Autorisierungs-/Eingabevalidierungsfehlers an einem KI-„Verbindungspunkt“: Ein
KI-Bildgenerierungs-Provider rief die in der Upstream-API-Antwort enthaltene URL mit einer
Allzweckfunktion ohne Scheme-Zulassungsliste ab. Bei Bereitstellungen, bei denen der konfigurierte Upstream
nicht der vertrauenswürdige Standard ist (Bring-Your-Own-Endpoint / Proxy / selbst gehostetes Gateway / kompromittiertes
Relay), konnte die Antwort den Server auf file:// oder eine interne Adresse verweisen.
Die nicht vertrauenswürdige Eingabe, die die Senke erreicht, ist die Upstream-Antwort-URL — nicht der Prompt des Benutzers.
file://-; die interne
Analyse des Autors ordnete es auch CWE-73 / CWE-441 zu.3.1 / bedingt 5.3
(Medium); frühere 6.5 / 7.4 zurückgezogen, und die mittlere Bewertung bestätigte dies.ai_provider_openai) < 1.1.1 und 1.2.0–1.2.1 (geprüft 1.2.1) auf Drupal Core 11.2Die gesamte Verifikation lief in einer eigenen, netzisolierten Sandbox gegen einen Mock-Upstream. Die echte OpenAI-API wurde nie aufgerufen. Leak-Orakel waren ausschließlich synthetisch.
Bestätigt (dynamisch demonstriert):
settings.php-Lesen bestätigt durch sha256-Byteabgleich (35,182 B) — Inhalt nie ausgegeben; DB-Anmeldedaten
sind daher im Umfang enthalten.Unverifiziert (ausdrücklich nicht behauptet):
Nicht betroffen: Standard-api.openai.com über TLS. Die host-Einstellung wird von Admin / Config-Sync / Deploy
gesteuert — ein Nicht-Admin-Angreifer zur Laufzeit kann sie nicht ändern.
Die Antwort-URL wurde an einen Allzweck-Fetch übergeben, der jeden registrierten PHP-Stream-Wrapper
(file, php, http, data, phar, …) berücksichtigt. response_format ist standardmäßig url, daher ist der
verwundbare Zweig der Standardpfad. file:// ist PHPs Standard-Dateisystem-Wrapper und wird nicht durch
allow_url_fopen abgeschirmt (eine frühere Behauptung „erfordert allow_url_fopen“ war falsch und wird zurückgezogen).
Behebe das Primitiv, nicht nur die Aufrufstelle:
http/https vor der Anfrage; deaktiviere Weiterleitungen (ein 30x kann zu file:// weiterleiten).file://…, http://169.254.169.254/… und eine 302→file://-Weiterleitung
müssen alle abgelehnt werden.Vollständige Richtung: 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)
Die Dokumentation ist derzeit japanisch (
.ja.md); englische kanonische Übersetzungen sind ein TODO. Aus diesem Repository zurückgehalten: scharfe Payloads und jeder schlüsselfertige Dateilesen-PoC. Das öffentlichereproducer/demonstriert den Fehlermechanismus gegen einen Mock mit einem einzigen unbedenklichen Orakel (/etc/hostname) — kein Lesen beliebiger Pfade, keinsettings.php-Abgriff, kein IMDS. Es ist keine Waffe gegen Live-Sites. Aktualisiere auf 1.1.1 / 1.2.2.
Ziel: einem Forscher ermöglichen, die Fehler-Klasse zu bestätigen, ohne einen Exploit für Live-Ziele bereitzustellen oder Geheimnisse offenzulegen. Alles läuft offline.
docker compose mit der App und einem Mock-Upstream in einem isolierten Netzwerk (--network none
für die Sprachprimitiv-Prüfungen). Keine Anmeldedaten eingehängt. Der Mock spricht nie mit der echten API.host, der auf ein nicht vertrauenswürdiges Proxy/selbst gehostetes
Gateway zeigt.“ Er wird out-of-band scharfgeschaltet (nicht über den Prompt), um eine synthetische Ziel-URL zurückzugeben — das kodiert
das korrigierte Angreifermodell (der Upstream wählt die URL, der Benutzer löst nur aus).file:///etc/hostname und ein pro Lauf eindeutiges Markerkennzeichen, das nur im App-Container geschrieben wird → beweist,
dass die App einen vom Upstream gewählten Pfad gelesen hat (Marker fehlt im Mock).settings.php verifiziert durch sha256-Byteabgleich, Inhalt nie ausgegeben → beweist „DB-Anmeldedaten im Umfang“,
ohne sie offenzulegen.0 ausnutzbar / 1 Vorbedingung /
2 nicht reproduziert / 3 Bereinigung fehlgeschlagen / 99 Fehler). Siehe reproducer/verdict.md.Siehe reproducer/README.md.
Siehe timeline.md. Zusammenfassung:
| Datum | Ereignis |
|---|---|
| 2026-06-10 | Statische Prüfung lokalisiert die Senke; file://-Lesen mit festem Pfad dynamisch bestätigt |
| 2026-06-11 | Lesen beliebiger Pfade + settings.php-sha256-Abgleich + internes HTTP-SSRF bestätigt |
| 2026-06-11 | Erreichbarkeit für Produktionsnutzer (Automator-interner Pfad; FWA legitimer HTTP-Exfil) |
| 2026-06-11 | Unabhängige Peer-Review korrigiert Übertreibungen (Angreifermodell, CVSS, allow_url_fopen); Einreichung auf HOLD gesetzt |
| 2026-06/07 | HOLD-Punkte geklärt; privat an das Drupal-Sicherheitsteam gemeldet; Basisklassen-Zwilling an drupal/ai gemeldet |
| 2026-07-10 | Behobene Versionen 1.1.1 / 1.2.2; Advisory SA-CONTRIB-2026-053 und CVE-2026-13233 veröffentlicht; Autor als Finder & Entwickler der Behebung genannt |
Praktiker-Erkennungen liegen in detections/; die Begründung in
docs/detection-engineering.md. Kurz gesagt:
169.254.169.254 / Loopback / RFC1918 in einem engen Zeitfenster nach dem API-Aufruf. Alarmiere nicht allein wegen Egress.file://-Lesezugriffe erreichen nie das Netzwerk — erkenne sensible Dateiöffnungen durch Webprozesse über Host-Auditierung
(auditd/EDR), basisliniert, sodass nur Musterabweichungen innerhalb einer Bildgen-Anfrage auslösen.image/* deklarierten Bytes, deren Magic Bytes kein Bild sind.{request_id, actor, target_url, scheme, resolved_ip, content_type} hinzu. Standardprotokolle allein werden das nicht erkennen.file:// ist der Standard-Dateisystem-Wrapper; nicht durch allow_url_fopen abgeschirmt)reproducer/ ist nur für Sandboxen und verwendet synthetische Orakel. Es ist kein Exploit für Live-Ziele und
enthält keine Geheimnisse. Führe es nicht gegen Systeme aus, die dir nicht gehören und für die du nicht zum Testen autorisiert bist.Die gesamte Forschung wurde vom Autor in einer selbst betriebenen, netzisolierten Sandbox gegen einen Mock-Upstream durchgeführt —
die echte Hersteller-API wurde nie kontaktiert und kein Drittsystem wurde jemals getestet. Der Befund wurde privat
zuerst an das Drupal-Sicherheitsteam gemeldet und nur synchron mit dem Fix und Advisory veröffentlicht
(SA-CONTRIB-2026-053, CVE-2026-13233); die Bewertung des Herstellers lautet Mäßig kritisch. Die CVSS-Zahlen des Autors
sind eine vorläufige Selbsteinschätzung, keine offizielle Bewertung, und wurden bewusst konservativ gehalten (kein
CVSS Critical/High) — konsistent mit der mittleren Bewertung des Herstellers. Dieses Material dient defensiven und
Bildungszwecken. Siehe SECURITY.md.