
CVE-2026-13233 (Drupal OpenAI Provider, SA-CONTRIB-2026-053) : SSRF par response-URL / lecture de fichiers locaux. Amont non fiable, pas l'invite. Reproducteur sûr + détections. Corrigé dans 1.1.1/1.2.2.
Amont non fiable : le fournisseur qui a récupéré l'URL que sa réponse lui indiquait.
Drupal OpenAI Provider (ai_provider_openai) · SSRF (CWE-918) · CVE-2026-13233 · SA-CONTRIB-2026-053
Statut : Divulgation coordonnée terminée (2026-07-10). Signalé en privé à l'équipe de sécurité Drupal, corrigé et publié comme CVE-2026-13233 / avis SA-CONTRIB-2026-053 (noté Modérément critique). L'auteur est crédité comme découvreur et développeur de la correction.
Une étude d'un défaut classique d'autorisation / de validation des entrées sur un « point de connexion » d'IA : un
fournisseur de génération d'images IA récupérait l'URL contenue dans la réponse de l'API amont à l'aide d'une
fonction générique sans liste blanche de schémas. Sur les déploiements où l'amont configuré
n'est pas la valeur par défaut de confiance (apportez-votre-propre-endpoint / proxy / passerelle auto-hébergée / relais
compromis), la réponse pouvait pointer le serveur vers file:// ou une adresse interne.
L'entrée non fiable qui atteint le puits est l'URL de réponse de l'amont — pas l'invite de l'utilisateur.
file:// ; l'analyse
interne de l'auteur l'a également rattachée à CWE-73 / CWE-441.3.1 / conditionnel 5.3
(Moyen) ; les 6.5 / 7.4 antérieurs sont rétractés, et la note moyenne l'a confirmé.ai_provider_openai) < 1.1.1 et 1.2.0–1.2.1 (audité 1.2.1) sur Drupal core 11.2Toute la vérification s'est déroulée dans un bac à sable détenu et isolé du réseau contre un amont simulé (mock). La vraie API OpenAI n'a jamais été appelée. Les oracles de fuite étaient uniquement synthétiques.
Confirmé (démontré dynamiquement) :
settings.php confirmée par correspondance d'octets sha256 (35 182 octets) — contenu jamais affiché ; les identifiants
de base de données sont donc concernés.Non vérifié (explicitement non revendiqué) :
Non concerné : api.openai.com par défaut sur TLS. Le réglage host est contrôlé par admin / config-sync / déploiement —
un attaquant non-admin au moment de l'exécution ne peut pas le modifier.
L'URL de réponse était passée à une récupération générique qui honore tous les wrappers de flux PHP
enregistrés (file, php, http, data, phar, …). response_format par défaut est url, donc la branche
vulnérable est le chemin par défaut. file:// est le wrapper de système de fichiers par défaut de PHP et n'est pas
conditionné par allow_url_fopen (une affirmation antérieure « nécessite allow_url_fopen » était erronée et est rétractée).
Corriger la primitive, pas seulement le site d'appel :
http/https avant la requête ; désactiver les redirections (un 30x peut rebondir vers file://).file://…, http://169.254.169.254/…, et une redirection
302→file:// doivent tous être refusés.Direction complète : docs/fix-direction.md.
.
├── README.md # ce fichier (anglais, canonique)
├── README_ja.md # miroir japonais
├── SECURITY.md # politique de signalement + avertissement de divulgation responsable
├── .gitignore # empêche les secrets / preuves primaires d'être commités
├── docs/
│ └── fix-direction.md # correction de cause racine + chasse aux variantes + esquisse de diff minimal (EN)
├── reproducer/ # reproducteur SÛR uniquement (bac à sable, amont simulé, oracle bénin)
│ ├── README.md # comment mettre en place le bac à sable isolé du réseau
│ ├── verdict.md # ce que « succès » signifie : correspondance d'octets brute + 200-vs-403 + codes de sortie
│ ├── mock-openai-server.py # mock bénin ; PNG par défaut du chemin nominal, ssrf_demo → file:///etc/hostname uniquement
│ └── docker-compose.yml # MODÈLE : bac à sable Drupal isolé + mock (vous ajoutez la cible vulnérable)
├── 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 # chronologie de divulgation (source unique de vérité)