
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é)
Les docs sont actuellement en japonais (
.ja.md) ; les traductions canoniques en anglais sont à faire. Retirés de ce dépôt : les payloads d'armement et tout PoC clé-en-main de lecture de fichier. Lereproducer/public démontre le mécanisme du défaut contre un mock en utilisant un seul oracle bénin (/etc/hostname) — pas de lecture de chemin arbitraire, pas de récupération desettings.php, pas d'IMDS. Ce n'est pas une arme contre des sites en production. Mettez à jour vers 1.1.1 / 1.2.2.
Objectif : permettre à un chercheur de confirmer la classe de défaut sans fournir d'exploit contre une cible réelle ni exposer de secrets. Tout fonctionne hors ligne.
docker compose avec l'application et un amont simulé sur un réseau isolé (--network none
pour les vérifications de primitives du langage). Aucun identifiant monté. Le mock ne parle jamais à la vraie API.host pointant vers un proxy / une passerelle auto-hébergée non fiable. »
Il est armé hors bande (pas via l'invite) pour renvoyer une URL cible synthétique — cela encode
le modèle d'attaquant corrigé (l'amont choisit l'URL, l'utilisateur ne fait que déclencher).file:///etc/hostname et un marqueur unique par exécution écrit uniquement dans le conteneur applicatif → prouve
que l'application a lu un chemin choisi par l'amont (marqueur absent sur le mock).settings.php vérifié par correspondance d'octets sha256, contenu jamais émis → prouve « identifiants de base de données concernés »
sans les divulguer.0 exploitable / 1 précondition /
2 non-reproduit / échec de nettoyage / erreur). Voir .Voir reproducer/README.md.
Voir timeline.md. Résumé :
Les détections pour praticiens se trouvent dans detections/ ; la justification dans
docs/detection-engineering.md. En bref :
169.254.169.254 / loopback / RFC1918 dans une fenêtre temporelle étroite après l'appel API. Ne pas alerter sur le seul
trafic sortant.file:// ne passent jamais par le réseau — détecter les ouvertures de fichiers sensibles par les processus web via l'audit
hôte (auditd/EDR), avec une ligne de base afin que seules les lectures hors motif au sein d'une requête de génération d'images déclenchent.image/* dont les octets magiques ne sont pas une image.{request_id, actor, target_url, scheme, resolved_ip, content_type}. Les journaux standard seuls ne suffiront pas à détecter cela.file:// est le wrapper de système de fichiers par défaut ; non conditionné par allow_url_fopen)reproducer/ est réservé au bac à sable et utilise des oracles synthétiques. Ce n'est pas un exploit contre des cibles réelles et
ne contient aucun secret. Ne l'exécutez pas contre des systèmes que vous ne possédez pas et n'êtes pas autorisé à tester.Toutes les recherches ont été menées par l'auteur dans un bac à sable auto-détenu et isolé du réseau, contre un amont simulé —
la vraie API du fournisseur n'a jamais été contactée, et aucun système tiers n'a jamais été testé. La découverte a été signalée
en privé à l'équipe de sécurité Drupal en premier et publiée uniquement en synchronisation avec la correction et l'avis
(SA-CONTRIB-2026-053, CVE-2026-13233) ; la note du fournisseur est Modérément critique. Les chiffres CVSS de l'auteur sont une
auto-évaluation provisoire, pas un score officiel, et ont été délibérément conservés prudents (pas de
CVSS Critique/Élevé) — conformes à la bande moyenne du fournisseur. Ce contenu est à des fins défensives et
pédagogiques. Voir SECURITY.md.
399| Date | Événement |
|---|
| 2026-06-10 | La revue statique localise le puits ; lecture file:// à chemin fixe confirmée dynamiquement |
| 2026-06-11 | Lecture de chemin arbitraire + correspondance sha256 de settings.php + SSRF HTTP interne confirmés |
| 2026-06-11 | Atteignabilité en conditions de production (chemin interne automator ; exfiltration HTTP légitime FWA) |
| 2026-06-11 | Une relecture indépendante par un pair corrige les sur-déclarations (modèle d'attaquant, CVSS, allow_url_fopen) ; soumission mise en HOLD |
| 2026-06/07 | Éléments de HOLD levés ; signalé en privé à l'équipe de sécurité Drupal ; jumeau de classe de base signalé à drupal/ai |
| 2026-07-10 | Versions corrigées 1.1.1 / 1.2.2 ; avis SA-CONTRIB-2026-053 et CVE-2026-13233 publiés ; auteur crédité comme découvreur et développeur de la correction |