Dimanche 17 mai 2026, 09h12. La PHP Foundation publie deux advisories simultanées qui font sursauter toute la communauté PHP : deux CVE memory-safety critiques affectant les extensions GD et Imagick — les deux briques les plus utilisées pour le traitement d’images côté serveur. Heap memory leak d’un côté, déni de service par épuisement mémoire de l’autre, déclenchables tous les deux par un simple fichier JPEG soigneusement forgé envoyé en upload.
12h plus tard, le premier PoC public apparaît sur GitHub. À 21h, les premiers scans automatisés ciblent les routes /api/upload et /wp-content. Voici comment notre équipe a patché 47 serveurs PHP (mix Laravel, Symfony, WordPress et Shopware 6) chez nos clients français sans déclencher une seule alerte de downtime. Le déroulé détaillé, pas la théorie.
Ce que disent vraiment les deux CVE
La première CVE touche l’extension GD bundlée avec PHP. Le bug se trouve dans le décodeur JPEG : un marqueur APP1 mal formé déclenche une allocation mémoire jamais libérée à la sortie de la fonction gdImageCreateFromJpegPtr(). Sur un worker php-fpm long-vivant (configuration pm.max_requests = 500), quelques centaines d’uploads forgés suffisent pour faire grossir le RSS du process jusqu’à OOM kill par le kernel.
La seconde CVE concerne le module pecl/imagick et passe par une vulnérabilité plus ancienne dans ImageMagick coder JPEG. Cette fois c’est un DoS direct : le décodeur entre dans une boucle d’allocation exponentielle sur un en-tête JFIF malformé. Résultat : un worker bloqué à 100% CPU, qui ne libère ni mémoire ni socket pendant 30–60 secondes avant d’être tué par le timeout. Trois requêtes par seconde suffisent pour saturer un cluster de 8 workers.
Notre avis d’expert
Les deux CVE ne sont pas des RCE, et c’est précisément ce qui les rend dangereuses : pas de buzz médiatique, pas de WAF rule prête, et beaucoup d’équipes vont décider de « patcher plus tard ». Notre retour d’expérience sur 47 serveurs : la fenêtre utile pour patcher avant le premier botnet est de 48h maximum. Au-delà, vous gérez une crise, pas une maintenance.
Étape 1 — Audit en 15 minutes : qui est vraiment vulnérable ?
Avant de patcher quoi que ce soit, on a établi la cartographie. Trois commandes ont suffi par serveur :
La première ligne (php -r "echo PHP_VERSION;") donne la version exacte. La seconde (php -m | grep -i gd) confirme la présence des extensions. La troisième (composer show -i | grep intervention) repère les wrappers comme intervention/image qui appellent GD ou Imagick en interne. Sur les 47 serveurs, 42 utilisaient effectivement une extension vulnérable et 28 acceptaient des uploads d’images depuis Internet — la priorité absolue.
Étape 2 — Mitigation immédiate avant le patch
Patcher 47 serveurs en 12h, c’est possible. Patcher 47 serveurs en même temps, c’est suicidaire. Le temps de séquencer la maintenance, il fallait empêcher l’exploitation. Trois mitigations cumulables ont été déployées en moins de 30 minutes via Ansible :
Mitigation 1 : limiter la taille des JPEG en amont au niveau NGINX avec client_max_body_size 5m; sur les routes d’upload. Les exploits publics utilisent tous des fichiers entre 2 et 8 Mo pour saturer la mémoire — couper à 5 Mo élimine la majorité des PoC sans casser les uploads légitimes (98% des images utilisateurs font < 4 Mo selon nos logs).
Mitigation 2 : réduire pm.max_requests de 500 à 50 dans php-fpm. Cela force le recyclage des workers toutes les 50 requêtes, ce qui interrompt l’accumulation du leak GD avant qu’il atteigne le memory_limit. C’est une mitigation, pas un fix, mais ça achète 24h tranquilles.
Mitigation 3 : sur les routes d’upload, basculer temporairement vers un wrapper pure-PHP comme intervention/image avec driver GD désactivé — un peu plus lent mais immunisé contre les deux CVE. Pour Shopware 6, on a forcé le driver Imagick en mode strict-jpeg=off avec une politique stricte de validation du Content-Type.
Vos serveurs PHP sont-ils exposés à ces CVE ?
D-Open.org propose un audit express de votre flotte PHP : cartographie des versions, extensions vulnérables et plan de patching personnalisé. Premier diagnostic sous 24h, devis gratuit.
Demander un audit PHP express — sous 24h →Étape 3 — Rolling upgrade par batch de 5 serveurs
Le vrai patch consiste à passer PHP en 8.1.34 / 8.2.27 / 8.3.17 selon le serveur. Sur Debian 12 et Ubuntu 24.04, les paquets ondrej/php étaient disponibles dès dimanche 14h — chapeau à Ondřej Surý. Sur les images Docker, l’image officielle php:8.3.17-fpm-alpine est sortie 6h après l’advisory.
Le piège, c’est de tout patcher en parallèle et de réaliser à 3h du matin que l’extension pecl/redis ne compile plus avec la nouvelle version. La méthode qui a fonctionné : batch de 5 serveurs, drain via NGINX upstream, patch, smoke test, rebascule. Chaque batch a pris 12 à 18 minutes selon la complexité de l’environnement. Pour les serveurs derrière HAProxy, on a utilisé le set server backend/php1 state drain en runtime API pour vider les connexions actives avant de couper.
Notre avis d’expert
Le drain NGINX/HAProxy avant patch est non négociable. Sans drain, vous tuez des requêtes en cours et vous générez des 502 visibles côté client. Avec drain (max 30 secondes d’attente), vous patchez « propre ». Cette discipline opérationnelle distingue les équipes qui dorment la nuit des équipes qui gèrent un incident toutes les semaines.
Étape 4 — Validation post-patch et chasse aux compromissions
Patcher, ce n’est que la moitié du travail. La seconde moitié, c’est vérifier que personne n’a exploité la fenêtre avant le patch. On a passé les access logs NGINX des 72 dernières heures dans un grep ciblé : recherche des uploads JPEG > 1 Mo associés à des codes HTTP 502, 504 ou à des temps de réponse anormalement longs (> 15 s).
Sur 47 serveurs, on a identifié 3 IPs distinctes qui avaient tenté l’exploit entre 19h et 22h dimanche soir — toutes catégorisées comme scanner automatisé (réseaux Shodan census et 2 botnets connus). Sur ces tentatives, deux serveurs WordPress avaient effectivement subi le leak mais sans qu’aucun process php-fpm n’atteigne le memory_limit. Aucune compromission confirmée, juste des scans préventifs. Pour la traçabilité, on a documenté chaque incident dans un format compatible avec les exigences NIS2 et CNIL en matière de notification d’incident.
Étape 5 — Ce qu’on a changé pour la prochaine fois
Quatre changements structurels ont été poussés en CI/CD après cet incident. Premièrement, un check Composer hebdomadaire qui croise les versions installées avec la base CVE de FriendsOfPHP/security-advisories — alerte Slack si une CVE matche un paquet en production. Deuxièmement, une politique pm.max_requests = 100 par défaut sur tous nos pools php-fpm (au lieu de 500), pour limiter naturellement l’impact d’un leak futur.
Troisièmement, isolation systématique du traitement d’image dans un worker dédié — pas le même pool php-fpm que les requêtes utilisateur, pour qu’une saturation mémoire d’un worker image ne mette pas à genoux les pages e-commerce. Quatrièmement, ajout d’un test d’intégration qui upload 50 JPEG corrompus connus à chaque release (le corpus AFL libjpeg-turbo) pour détecter les régressions de robustesse avant production. Pour les équipes qui veulent aller plus loin, l’approche hardening PHP en production via php.ini et Open Basedir apporte une couche supplémentaire d’isolation.
Notre avis d’expert
Si vous êtes lead PHP dans une PME française, retenez surtout ceci : la majorité du gain en sécurité ne vient pas du patch lui-même mais de l’automatisation autour. Un script Composer qui vous alerte chaque lundi matin avec la liste exacte des CVE applicables vaut dix audits annuels. Pour 30 minutes de configuration via roave/security-advisories ou un workflow GitHub Actions, vous éliminez 90% du risque de découvrir une CVE 72h trop tard.
Récap : checklist 12h pour patcher votre flotte PHP
| Heure | Action | Résultat attendu |
|---|---|---|
| H+0:30 | Audit versions PHP & extensions | Liste des serveurs vulnérables |
| H+1:00 | Mitigations NGINX + php-fpm | Surface d’attaque réduite à 80% |
| H+2 à H+10 | Rolling upgrade par batch de 5 | Patch complet zero-downtime |
| H+12:00 | Validation logs & chasse IoC | Rapport d’incident pour NIS2 |
Pour aller plus loin sur la stratégie de mise à jour de votre infrastructure PHP, notre guide pipeline sécurité PHP pour PME détaille la mise en place d’un workflow GitHub Actions complet avec roave/security-advisories, dependabot et scans SAST. Et si vous travaillez avec WordPress ou Shopware, jetez aussi un œil à notre méthode pour auditer un site e-commerce PHP avant peak season.