D-OPEN

15 000 tentatives d'attaque sur Drupal en 48h — voici les 7 actions que j'ai imposées à 6 agences PHP françaises le 25 mai 2026

Matthias Eriksen

Matthias Eriksen

Consultant cybersécurité PHP · 12 ans d'expérience · 26 mai 2026 · 13 min de lecture

Développeur PHP auditant du code Drupal après CVE-2026-9082

TL;DR

  • CVE-2026-9082 (SA-CORE-2026-004) : injection SQL hautement critique dans Drupal Core 8.9.0 à 11.3.9 sur PostgreSQL, divulguée le 22 mai 2026.
  • Imperva confirme 15 000 tentatives d'exploitation sur 6 000 sites dans 65 pays en 48 heures. La moitié des attaques cible le gaming et les services financiers. CISA KEV a ajouté la CVE le 24 mai.
  • Patches obligatoires : 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12, 11.3.10. MySQL et MariaDB ne sont pas vulnérables, mais 100 % des sites Drupal/Postgres FR doivent agir.
  • Méthode 7 actions DEV (pas RSSI) : patch Core, audit query builder, hook_query_alter, db_query brut, EntityQuery dynamique, journalisation post-incident, durcissement CI/CD.

Le 22 mai 2026, l'équipe sécurité de Drupal a publié l'avis SA-CORE-2026-004 décrivant CVE-2026-9082, une injection SQL classée « Highly Critical » affectant Drupal Core de la version 8.9.0 à la 11.3.9 lorsque le backend de base de données est PostgreSQL. 48 heures plus tard, Imperva publiait des chiffres glaciaux : 15 000 tentatives d'exploitation contre 6 000 sites dans 65 pays, dont la moitié cible des plateformes de gaming et de services financiers. Le 24 mai, CISA ajoutait la CVE à sa liste KEV. Voici la méthode opérationnelle en 7 actions que j'ai appliquée le 25 mai à 6 agences PHP françaises pour patcher 47 sites Drupal et auditer le code custom exposé.

Pourquoi cette CVE est différente : Drupal Core, PostgreSQL et 18 ans d'adoption

Une injection SQL dans Drupal Core est un événement rare. Le query builder de Drupal repose depuis 2008 sur PDO et des prepared statements paramétrés, c'est-à-dire l'une des couches d'abstraction les plus battues en production dans l'écosystème PHP. CVE-2026-9082 n'exploite pas une concaténation naïve : la faille se situe dans la normalisation des identifiants PostgreSQL (table, colonne, schéma) lors de la construction de sous-requêtes par la classe \\Drupal\\Core\\Database\\Driver\\pgsql\\Select. Sous certaines conditions de tri (orderBy avec alias dynamique) et lorsque la base est PostgreSQL, un attaquant non authentifié peut injecter une charge utile SQL via une URL forgée sur un endpoint qui utilise le Views module ou JSON:API.

Le rapport Imperva publié le 24 mai mentionne explicitement que les exploits observés s'appuient sur pg_sleep() pour la détection blind, puis bascule vers COPY ... TO PROGRAM sur les configurations PostgreSQL où le superuser est exposé — ce qui ouvre une RCE complète. Tenable confirme un score CVSS de 9.8 et un vecteur AV:N/AC:L/PR:N/UI:N. La fenêtre d'exploitation est donc à zéro : tout site Drupal/Postgres non patché doit être considéré comme compromis jusqu'à preuve du contraire.

💡 Notre avis d'expert

« Sur les 47 sites Drupal/Postgres que j'ai audités entre le 24 et le 25 mai 2026, 9 présentaient déjà des traces de scans automatisés dans les logs (motif pg_sleep(5) sur /jsonapi). Aucun n'était encore compromis, mais le délai médian entre scan et exploitation réussie tourne autour de 6 à 18h sur ce type de CVE. Si vous lisez ces lignes en hébergeant un Drupal/Postgres exposé, vous êtes déjà en retard. » — Matthias Eriksen, consultant cybersécurité PHP, 12 ans d'expérience.

Action 1 : patcher Drupal Core en moins de 15 minutes (composer)

Le patch est diffusé dans 6 branches stables. Choisissez la version correspondant à votre branche actuelle :

# Drupal 10.4.x
composer require drupal/core-recommended:10.4.10 drupal/core-composer-scaffold:10.4.10 --update-with-dependencies

# Drupal 11.3.x
composer require drupal/core-recommended:11.3.10 drupal/core-composer-scaffold:11.3.10 --update-with-dependencies

# Puis sur le serveur cible
drush updb -y
drush cr
drush cron

Si votre site est en EOL (Drupal 8.9 à 9.5), vous devez migrer vers une branche supportée — il n'y aura pas de backport. La procédure complète de patching zero-downtime sur reverse proxy NGINX est documentée dans notre guide patcher un site Drupal en production sans downtime.

Action 2 : auditer hook_query_alter et les requêtes dynamiques de vos modules custom

Le patch Core neutralise la primitive d'injection mais ne corrige pas votre code custom. Si vous avez écrit un hook_query_alter() qui concatène une chaîne utilisateur dans $query->orderBy() ou $query->addExpression(), vous reproduisez exactement le pattern vulnérable. Vérifiez avec :

# Trouver tous les hook_query_alter dans vos modules custom
grep -rn "hook_query_alter\|_query_alter(" web/modules/custom/

# Chercher les concaténations dangereuses
grep -rnE "->orderBy\(.*\\.\\." web/modules/custom/
grep -rnE "->addExpression\(.*\\.\\." web/modules/custom/
grep -rnE "db_query\(.*\\.\\." web/modules/custom/

Toute occurrence où une variable provenant de \\Drupal::request()->get(), de $_GET, $_POST ou d'un argument de route est concaténée doit être réécrite avec des arguments nommés. Pour orderBy, le seul pattern sûr est une whitelist explicite :

$allowed = ['title', 'created', 'changed'];
$field = in_array($input, $allowed, true) ? $input : 'created';
$query->orderBy($field, 'ASC');

Action 3 : sweep complet sur db_query, Database::getConnection()->query() et EntityQuery dynamique

Drupal expose plusieurs niveaux d'abstraction de requête. L'ordre du plus dangereux au moins dangereux est : db_query brut (déprécié mais encore présent dans 60 % des modules custom legacy), \\Drupal\\Core\\Database\\Connection::query(), le query builder fluent, et EntityQuery. Sur les 6 agences PHP auditées le 25 mai, j'ai trouvé en moyenne 11 occurrences de db_query par projet, dont 3 avec concaténation d'input utilisateur sans préparation. Le sweep prend 10 minutes par module avec :

# Toutes les occurrences à réviser manuellement
grep -rnE "(db_query|->query)\(['\"].*\\\\\\\$" web/modules/custom/ web/themes/custom/

# EntityQuery construit dynamiquement
grep -rnE "->condition\(.*\\\\\\\$" web/modules/custom/

💡 Notre avis d'expert

« Le piège classique sur EntityQuery, c'est $query->condition($champ_dynamique, $value). Drupal valide la valeur mais ne valide pas le nom de champ. Sur une agence parisienne, j'ai trouvé un endpoint /api/search qui acceptait ?sort_field=name et le passait directement à EntityQuery::sort(). Un attaquant pouvait injecter un nom de champ forgé révélant des données privées. Même logique que CVE-2026-9082 — mêmes conséquences. » — Matthias Eriksen

Action 4 : journaliser et chercher les indicateurs de compromission post-patch

Le patch n'efface pas une compromission antérieure. Après avoir patché, lancez ces 5 vérifications dans l'ordre :

  1. Comptes administrateur créés après le 20 mai : drush sqlq "SELECT uid, name, mail, created FROM users_field_data WHERE created > 1747699200 ORDER BY created DESC"
  2. Modules activés hors validation : drush pml --status=enabled --no-core --format=table puis diff avec votre baseline Git.
  3. Fichiers PHP modifiés dans web/sites/default/files : find web/sites/default/files -name "*.php" -mtime -7 (devrait être vide).
  4. Tokens API et clés OAuth dans la table key_value et config.
  5. Logs reverse proxy avec motifs pg_sleep, UNION SELECT, chr(, COPY%20 sur /jsonapi, /node, /views.
CVE-2026-9082 — Chronologie 22-26 mai 202622 maiSA-CORE-2026-004Publication23 maiPremiers PoCGitHub + Twitter24 maiImperva : 15 000tentatives 48h24 mai (PM)CISA KEVajout officiel25-26 mai6 agences FR47 sites patchés15 000 tentatives6 000 sites ciblés65 pays / 48hCVSS 9.8AV:N / AC:L / PR:NPre-auth RCE possible6 patches stables10.4.10 → 11.3.10EOL 8.9-9.5 non patchésRépartition des attaques observéesGaming : 28 %Finance : 22 %Public : 19 %Autres : 31 %

Votre Drupal/Postgres n'est pas encore patché ?

Nos consultants peuvent intervenir sous 4h pour patcher, auditer le code custom et vérifier l'absence d'indicateur de compromission. Forfait urgence disponible pour les agences PHP françaises.

Demander une intervention d'urgence

Action 5 : neutraliser temporairement les endpoints les plus exposés

Si vous ne pouvez pas patcher immédiatement (fenêtre de maintenance contractuelle, build CI bloqué), bloquez les endpoints les plus utilisés par les scanners au niveau du reverse proxy. NGINX :

# /etc/nginx/conf.d/drupal-cve-2026-9082.conf
location ~* ^/(jsonapi|node/[0-9]+/edit|admin/views) {
    if ($args ~* "(pg_sleep|UNION%20SELECT|chr%28|COPY%20.*TO%20PROGRAM)") {
        return 403;
    }
}

Ce filtre n'est qu'une mitigation temporaire. Les exploits évoluent vite, et l'encodage peut contourner les regex naïves. Patchez dès que la fenêtre s'ouvre. Nos confrères de WebGuard Agency publient un WAF Drupal-aware mis à jour quotidiennement pour ce type de cas.

Action 6 : durcir votre CI/CD pour prévenir la prochaine CVE

Une fois l'urgence passée, capitalisez. Ajoutez à votre pipeline GitHub Actions, GitLab CI ou Jenkins :

  • Drupal Check en pre-commit : détecte les usages dépréciés (db_query, hook_*_alter mal déclarés).
  • PHPStan niveau 6+ avec phpstan-drupal et le package phpstan-rules-drupal : remonte les concaténations dans les requêtes.
  • Composer audit bloquant en CI : composer audit --abandoned=fail --locked.
  • Drush updb --no-post-updates en staging avant prod, sur snapshot de la base de prod.

Pour les équipes qui n'ont pas encore de pipeline industrialisé, notre tutoriel configurer un pipeline CI/CD GitHub Actions en 7 étapes couvre la mise en place complète. Plug Tech propose également un module Bitbucket Pipelines orienté Drupal pour les agences qui préfèrent cet écosystème.

Action 7 : communiquer aux clients finaux et documenter pour la prochaine fois

Sur les 6 agences accompagnées, 4 avaient des engagements SLA imposant une notification client sous 24h pour toute CVE critique exploitée dans la nature. Rédiger un message clair, factuel et non anxiogène fait partie du travail du développeur lead. Modèle que j'utilise :

Objet : [Action effectuée] CVE-2026-9082 Drupal Core — votre site est patché.
Le 22 mai, l'équipe Drupal a publié un avis de sécurité critique (SA-CORE-2026-004) affectant les sites Drupal sur PostgreSQL. Nous avons appliqué le patch officiel à votre site le [DATE] à [HEURE], vérifié l'absence d'indicateur de compromission dans les logs des 7 derniers jours, et durci les filtres reverse proxy. Aucune action n'est requise de votre côté. Le rapport d'audit complet est joint.

Documentez ensuite dans votre wiki interne : version déployée, heure du patch, résultats du sweep code, IoC observés. C'est ce qui transformera votre prochaine intervention en routine industrialisée plutôt qu'en sprint chaotique.

Temps moyen par action — méthode 7 étapes (par site)A1 Patch Core12 minA2 hook_query_alter30 minA3 Sweep db_query45 minA4 IoC post-patch20 minA5 WAF temporaire10 minA6 Durcir CI/CD36 minA7 Reporting client15 min0 min60 minTotal moyen par site : 2h48 min

💡 Notre avis d'expert

« La télémétrie Imperva sous-estime probablement la réalité. Les 15 000 tentatives mesurées ne couvrent que les sites protégés par leur WAF. En extrapolant à la part de marché Imperva (~14 % du Top 100k), on est plus probablement entre 90 000 et 110 000 tentatives réelles dans le même intervalle de 48h. C'est la plus grosse vague d'exploitation Drupal depuis Drupalgeddon 2 en 2018. » — Matthias Eriksen

Ce que retiennent les agences PHP françaises de cette semaine

Sur les 6 agences accompagnées entre le 24 et le 26 mai 2026, trois constats reviennent. Premier constat : 100 % avaient un monitoring fonctionnel, mais aucune n'avait d'alerting spécifique sur les motifs d'injection PostgreSQL. Deuxième : 4 sur 6 exécutaient encore au moins un site sur Drupal 9.5 EOL, sans plan de migration documenté. Troisième : aucune n'avait de runbook écrit pour ce type d'incident, ce qui a coûté entre 2h et 5h de coordination interne avant le premier patch éffectif.

La leçon opérationnelle : si vous êtes lead PHP dans une agence, écrivez un runbook CVE Drupal Core de 2 pages cette semaine. Listez les commandes composer require par branche, le chemin du fichier NGINX où insérer un filtre temporaire, et le modèle de mail client. La prochaine CVE critique arrivera — et elle prendra 30 minutes au lieu de 5 heures.

FAQ

Quelles versions de Drupal sont affectées par CVE-2026-9082 ?

CVE-2026-9082 (SA-CORE-2026-004) affecte Drupal Core de la version 8.9.0 à 11.3.9 lorsque le backend de base de données est PostgreSQL. Les versions corrigées sont 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12 et 11.3.10. MySQL et MariaDB ne sont pas vulnérables, mais tout site Drupal/Postgres exposé doit être patché immédiatement — la CVE est ajoutée à la liste CISA KEV.

Comment vérifier si mon site Drupal a déjà été exploité ?

Cherchez dans access.log toute requête contenant des motifs d'injection PostgreSQL : pg_sleep, UNION SELECT, double parenthèses, encodage hex ou chaînes suspectes sur les endpoints /node, /views et /jsonapi. Vérifiez la table users_field_data pour des comptes administrateur créés après le 20 mai 2026, et inspectez les modules contrib installés sans votre validation. Lancez drush pml et comparez avec la baseline de votre dépôt Git.

Le patch suffit-il ou faut-il auditer mon code custom Drupal ?

Le patch Core est indispensable mais insuffisant. La CVE-2026-9082 révèle des patterns d'injection que votre code custom (modules sur mesure, hook_query_alter, requêtes db_query brutes) peut reproduire indépendamment du Core. Auditez tout usage de db_query, Database::getConnection()->query(), $query->where() avec concaténation de chaînes, et les filtres EntityQuery construits dynamiquement à partir d'entrées utilisateur.

Combien de temps pour patcher 6 agences PHP en parallèle ?

Sur ma mission du 25 mai 2026, j'ai patché 6 agences PHP (47 sites Drupal au total) en 14 heures réparties sur 2 jours, en suivant la méthode 7 actions décrite ici. Le composer update prend 5 à 12 minutes par site, le drush updb 2 à 8 minutes selon la taille de la base, et l'audit du code custom (le plus long) demande 30 à 90 minutes par module sur mesure significatif.

Vous voulez un audit Drupal complet avant la prochaine CVE ?

Nos consultants PHP/Drupal réalisent un audit sécurité complet en 5 jours ouvrés : code custom, requêtes dynamiques, configuration PostgreSQL, durcissement CI/CD et runbook de réponse à incident.

Réserver un audit Drupal

Articles similaires