PHP2Shell désigne deux vulnérabilités critiques dans PHP lui-même, CVE-2026-109618 et CVE-2026-109619, qui peuvent permettre à une requête web non authentifiée d'exécuter du code sur toute installation PHP qui sert des requêtes web : PHP-FPM, Apache avec mod_php, php-cgi, FrankenPHP et LiteSpeed. Toutes deux sont exploitées dans la nature et inscrites au catalogue KEV de la CISA. Le correctif est PHP 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 ; PHP 8.1 et les versions antérieures n'ont aucune version upstream. Mettez à niveau, puis reconstruisez et redéployez chaque image de conteneur qui embarque PHP, y compris les anciens tags encore en service et les images livrées à vos clients.
Corriger le serveur que vous connaissez est la partie facile. L'exposition qui persiste, c'est le PHP que vous avez oublié : un runtime compilé dans une image de base, un tag d'image de l'an dernier qui tourne encore en production, une image de CI, ou un produit livré à des clients avec un PHP en fin de vie. Cette page vous aide d'abord à corriger, puis montre comment trouver le reste.
Ce qui s'est passé
| Date (2026) | Événement | Source |
|---|---|---|
| 11 et 21 août | Calif signale les deux bogues au projet PHP | Calif |
| 17 octobre | La première tentative d'exploitation observée par Amazon dans ses honeypots, avant la divulgation | Amazon Threat Intelligence |
| 20 octobre | PHP annonce une version de sécurité pour le 21 octobre, 14:00 UTC, corrigeant deux vulnérabilités notées CVSS 4.0 9,2 | php.net |
| 21 octobre | PHP publie 8.5.12, 8.4.27, 8.3.36 et 8.2.35 ainsi que son avis ; les enregistrements CVE deviennent publics ; le NCSC-NL ouvre son dépôt php2shell | Avis PHP, NCSC-NL |
| 21 octobre | Les images Docker officielles php sont mises à jour vers les versions corrigées | docker-library/php |
| 21 octobre | watchTowr signale l'exploitation des deux CVE dans la nature ; la CISA publie une alerte | watchTowr, CISA |
| 22 octobre | Searchlight Cyber publie php2shell-scanner | GitHub |
| 23 octobre | PHP conseille de définir session.upload_progress.enabled=0 contre un vecteur RCE distinct et peu probable, CVE-2026-115560 | php.net |
| 26 octobre | La CISA ajoute les deux CVE au catalogue KEV, avec une échéance au 29 octobre pour les agences fédérales américaines | CISA KEV |
Le nom PHP2Shell vient de l'analyse de Calif et s'est imposé dans la couverture du secteur ; les avis de PHP lui-même ne l'emploient pas. Les enregistrements CVE créditent Calif, Wiz et OpenAI.
Qui est concerné
Tout PHP qui sert des requêtes web. L'avis de PHP cite PHP-FPM, Apache avec mod_php, php-cgi, FrankenPHP et LiteSpeed, et estime le risque le plus élevé pour mod_php, « avec un exploit démontré où une requête non authentifiée peut déclencher l'attaque avant l'exécution de tout code applicatif ». Comme les bogues se trouvent dans PHP lui-même, les applications bâties sur Laravel, Symfony ou WordPress sont exposées dès lors que le PHP sous-jacent l'est.
| Branche | Affectées | Corrigée dans | Support upstream |
|---|---|---|---|
| 8.5 | avant 8.5.12 | 8.5.12 | Actif |
| 8.4 | avant 8.4.27 | 8.4.27 | Actif |
| 8.3 | avant 8.3.36 | 8.3.36 | Correctifs de sécurité uniquement, jusqu'au 31 décembre 2027 |
| 8.2 | avant 8.2.35 | 8.2.35 | Correctifs de sécurité uniquement, jusqu'au 31 décembre 2026 |
| 8.1, 8.0, 7.4 | toutes les versions, selon Calif et watchTowr | aucune version ; backports minimaux du code source dans php-src | Fin de vie |
| 7.3 et antérieures, dont PHP 5 | toutes les versions, selon Calif et watchTowr | aucun correctif upstream | Fin de vie |
Les avis de PHP ne listent que les branches prises en charge. Pour les plus anciennes, Calif indique que « le plus ancien chemin affecté que nous avons trouvé remonte à PHP 5.4.0 », et watchTowr liste PHP 7 et PHP 5 comme affectés sans correctif. PHP précise que les branches 8.1 et antérieures « ne reçoivent plus de mises à jour du projet PHP », mais il a publié des backports minimaux du code source pour 7.4, 8.0 et 8.1 à l'intention de ceux qui compilent depuis les sources. Certaines distributions et certains fournisseurs commerciaux de support à long terme livrent des correctifs rétroportés pour les branches en fin de vie ; renseignez-vous auprès du vôtre. Si vous testez la prochaine version majeure, PHP 8.6.0 RC4, publiée le même jour, contient elle aussi les correctifs.
Comment ça marche
Les deux CVE sont des bogues de sécurité mémoire dans la façon dont PHP prépare puis démonte une requête, sous tout code applicatif. Les enregistrements CVE classent les deux comme use after free (CWE-416), ainsi que comme gestion incorrecte de conditions exceptionnelles, accès à un pointeur non initialisé, allocation mémoire non maîtrisée et initialisation incorrecte (CWE-755, CWE-824, CWE-1325, CWE-1419). Dans les termes de PHP :
- CVE-2026-109618, RCE par corruption OOM : « la gestion d'un manque de mémoire peut interrompre PHP alors que des données internes de la requête ne sont que partiellement initialisées. Le nettoyage de la requête peut alors traiter les données invalides comme valides. » Un corps de requête conçu pour épuiser la mémoire pendant que PHP l'analyse peut déclencher cette sortie. Apache avec mod_php exécute le nettoyage même lorsque le démarrage de la requête a échoué, ce qui explique pourquoi l'attaque y fonctionne avant l'exécution de tout code applicatif. Pour PHP-FPM, l'avis de PHP indique que l'analyse du code source le donne pour vulnérable, même si aucun exploit FPM complet n'a été démontré.
- CVE-2026-109619, RCE par état global périmé : « un état interne propre à une requête peut subsister après la libération de la mémoire qui le porte. Une requête ultérieure traitée par le même worker peut utiliser cet état périmé avant que l'initialisation normale ne le réinitialise. » Il faut deux requêtes qui atteignent le même worker : l'une qui laisse l'état derrière elle, par exemple via une erreur fatale, et l'autre qui l'utilise. L'avis de PHP confirme le chemin de la progression d'envoi de session contre mod_php et FPM, et le chemin des backtraces d'erreurs fatales de PHP 8.5 contre mod_php.
C'est pourquoi les paramètres provisoires de PHP visent les limites de mémoire, la taille du corps de requête, la progression d'envoi de session et les backtraces d'erreurs fatales : chacun ferme un chemin vers les bogues, pas les bogues eux-mêmes. PHP, en tant que CNA, note les deux 9,2 selon CVSS 4.0. Les évaluations CVSS 3.1 propres au NVD sont de 9,8 pour CVE-2026-109618 et de 8,1 pour CVE-2026-109619.
Comment vérifier si vous êtes concerné
Commencez par les hôtes que vous connaissez, puis cherchez PHP dans tout ce que vous construisez et livrez.
Sur un hôte ou une VM, vérifiez la version que PHP annonce. Vérifiez aussi la SAPI web, car php-fpm ou le module Apache peuvent provenir d'un autre paquet que la ligne de commande :
php -v
php-fpm -v
Les paquets des distributions (Debian, Ubuntu, Alpine, RHEL) reçoivent souvent le correctif sous forme de backport, sans nouvelle version upstream : Ubuntu 24.04, par exemple, livre le correctif en 8.3.6-0ubuntu0.24.04.13. Une simple vérification de version est ici trompeuse. Listez le paquet installé et comparez-le à la version corrigée indiquée dans le suivi de sécurité de votre distribution :
dpkg -l 'php*' | grep '^ii' # Debian, Ubuntu
apk info -v | grep '^php' # Alpine
rpm -qa 'php*' # RHEL, Fedora, Rocky, Alma
Dans les images de conteneurs. Les images php: officielles compilent PHP depuis les sources : la version se trouve donc dans l'image elle-même, pas dans une liste de paquets de distribution. Interrogez directement l'image :
docker run --rm --entrypoint php php:8.3-fpm -v
Pour vérifier chaque image que vous exécutez réellement, listez-les et interrogez-les une à une. Pour Kubernetes :
kubectl get pods -A \
-o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' \
| sort -u \
| while read -r image; do
version=$(docker run --rm --entrypoint php "$image" -r 'echo PHP_VERSION;' 2>/dev/null)
printf '%s\t%s\n' "${version:-no php}" "$image"
done
Les images construites FROM debian ou FROM alpine avec PHP installé par le gestionnaire de paquets nécessitent la vérification des paquets ci-dessus, exécutée dans l'image.
Dans vos dépôts, cherchez chaque endroit où PHP est choisi :
git grep -nE '^FROM[[:space:]]+(.*/)?php:' -- '*Dockerfile*' '*.dockerfile'
git grep -nE 'php-version|image:.*php' -- .github/workflows '*.yml' '*.yaml'
Les tags épinglés comme php:8.3.30-fpm restent vulnérables jusqu'à ce que quelqu'un les modifie. Les tags flottants comme php:8.3-fpm ont été reconstruits avec les versions corrigées à partir du 21 octobre, mais une image construite avant cette date conserve l'ancien PHP tant que vous ne la reconstruisez pas. La contrainte php dans composer.json indique quelles versions votre code accepte, pas laquelle tourne.
En CI. Les jobs de build et de test utilisent souvent leur propre PHP : un conteneur de service php:, une action de configuration avec une entrée php-version, ou une image de runner. Ils ne servent pas de trafic de production, mais ils montrent quelles images et quelles versions votre pipeline produit.
Les hôtes exposés. Le php2shell-scanner de Searchlight Cyber sonde une URL avec de grosses requêtes multipart, environ 29 MiB par chemin. Ne l'utilisez que contre des hôtes que vous êtes autorisé à tester. Son README met en garde contre des faux positifs sur un PHP corrigé avec un memory_limit bas, et lorsque PHP ne divulgue pas sa version, le scanner ne peut pas distinguer un serveur corrigé d'un serveur vulnérable. Considérez-le comme un indice, pas comme une preuve. Le dépôt du NCSC-NL rassemble des règles de détection et une liste des produits qui embarquent PHP, avec leur statut.
Ce que l'analyse d'aujourd'hui ne peut pas vous dire. Analyser aujourd'hui les images de votre registre couvre ce que vous déploieriez aujourd'hui. Cela ne couvre pas une version antérieure livrée à un client, l'ancien tag qu'un client fait encore tourner, ni lesquels de vos builds ont produit des images avec un PHP vulnérable. Pour cela, il vous faut une trace de ce que chaque build a intégré, par version. Consultez sommes-nous concernés ? Comment évaluer une nouvelle CVE sur l'ensemble de vos builds.
Comment corriger, et que faire si vous ne pouvez pas encore appliquer le correctif
- Mettez à niveau vers 8.5.12, 8.4.27, 8.3.36 ou 8.2.35, ou vers le paquet corrigé de votre distribution. Sur 8.1 ou une version antérieure, passez à une branche prise en charge ; les backports de PHP et les builds de fournisseurs sont des solutions d'attente.
- Reconstruisez chaque image à partir d'une base corrigée (récupérez à nouveau l'image de base, ou construisez sans cache) et redéployez. Les images déjà en cours d'exécution gardent leur ancien PHP jusqu'à leur remplacement : redémarrez donc aussi les workloads.
- Vérifiez avec la liste de contrôle ci-dessous, sur les conteneurs en cours d'exécution, pas seulement sur la nouvelle image.
Si vous ne pouvez pas encore mettre à niveau, l'avis de PHP liste des mesures qui « réduisent l'exposition à certains chemins d'attaque mais ne rendent pas une installation sûre ». Pour CVE-2026-109618 :
- « Définissez
memory_limit=-1, de préférence d'une manière que les applications ne peuvent pas surcharger, par exemple avecphp_admin_valuedans le pool FPM ou la configuration Apache, et vérifiez qu'aucun paramètre de pool, de répertoire ou d'application ne rétablit une limite finie. » - « Pour les applications qui n'ont pas besoin d'envois de fichiers, définissez
post_max_size = 8M. Si les envois de fichiers sont nécessaires, définissezpost_max_size = 32M. Gardezupload_max_filesizeen dessous depost_max_size. » - Utilisez une limite mémoire de conteneur ou de cgroup comme limite de disponibilité, et ne la remplacez pas par
RLIMIT_ASouRLIMIT_DATA, « car ceux-ci peuvent provoquer l'échec d'allocation vulnérable ».
Pour CVE-2026-109619 :
- « Définissez
session.upload_progress.enabled=0et redémarrez chaque worker. Utilisezphp.ini, un pool FPM ou une configuration serveur qui s'applique avant l'analyse de la requête. Ne vous fiez pas àini_set()ni au.user.inide FPM. » - « Sur PHP 8.5, définissez
fatal_error_backtraces=0et redémarrez chaque worker. »
Vérifiez avec quels paramètres chaque worker tourne réellement :
php-fpm -i | grep -E 'memory_limit|post_max_size|session.upload_progress.enabled'
L'alerte de la CISA va plus loin : les organisations qui ne peuvent pas mettre à jour immédiatement, ou qui font encore tourner PHP 8.1 ou une version antérieure, « devraient mettre hors ligne les systèmes basés sur PHP jusqu'à ce qu'ils puissent être corrigés ou mis à jour ». Elle conseille aussi de surveiller les processus worker PHP qui lancent des shells ou téléchargent des outils.
Vérifier le correctif
- Interrogez le PHP en cours d'exécution, pas l'image que vous pensiez déployer. Exécutez
php-fpm -v(ouphp -v) dans chaque conteneur en cours d'exécution et sur chaque hôte, et confirmez 8.5.12, 8.4.27, 8.3.36, 8.2.35 ou une version ultérieure. - Ne vous fiez pas à la seule chaîne de version des paquets de distribution. Debian, Ubuntu, RHEL et d'autres distributions rétroportent le correctif dans la version qu'elles livrent déjà : un PHP corrigé peut donc toujours annoncer 8.3.6. Le correctif d'Ubuntu 24.04 est
8.3.6-0ubuntu0.24.04.13. Comparez la version complète du paquet avec le suivi de sécurité de votre distribution, ou cherchez la CVE dans le changelog du paquet, qui la cite généralement. Le piège fonctionne aussi dans l'autre sens : un scanner qui ne compare que les numéros de version upstream peut signaler comme vulnérable un paquet rétroporté. - Vérifiez que chaque workload exécute l'image reconstruite. Un tag qui pointe désormais vers une image corrigée ne change rien à un pod qui a récupéré l'ancienne. Comparez le digest d'image que chaque conteneur exécute avec celui que vous avez construit :
kubectl get pods -A \
-o jsonpath='{range .items[*]}{range .status.containerStatuses[*]}{.image}{"\t"}{.imageID}{"\n"}{end}{end}'
- Vérifiez que chaque worker a redémarré. PHP-FPM et Apache gardent l'ancien code chargé jusqu'à leur redémarrage ; la vérification des processus sous « Rechercher une compromission » montre ceux qui l'exécutent encore.
- Si vous comptez encore sur les paramètres provisoires, vérifiez chaque pool avec la commande
php-fpm -ici-dessus, et conservez-les jusqu'à ce que la mise à niveau soit faite partout. - Refaites l'inventaire de la section de vérification sur votre registre, vos images de CI et les versions que vos clients exécutent, pas seulement en production.
Rechercher une compromission
PHP2Shell est exploitée dans la nature, et Amazon a observé la première tentative le 17 octobre 2026, quatre jours avant le correctif. Si un PHP exposé à Internet a fait tourner une version affectée sans les paramètres provisoires à un moment quelconque depuis, vérifiez-le.
L'ampleur de l'exposition. Les décomptes de bannières Shodan publiés par Mallory le 20 octobre, rapportés par CybelAngel, ont trouvé 2,24 millions d'hôtes exposés à Internet qui annoncent PHP ; sur les quelque 1,5 million qui affichent une version, 883 717 (59 %) font tourner une branche sans correctif officiel. Ces chiffres comptent des hôtes, pas des systèmes dont la vulnérabilité est confirmée : des paquets rétroportés peuvent sembler anciens tout en étant corrigés, et environ 740 000 hôtes masquent leur version.
Appliances et produits qui embarquent PHP. PHP tourne aussi dans des appliances, des équipements réseau, des interfaces d'administration et des produits de fournisseurs où vous ne pourrez peut-être pas le mettre à jour vous-même. L'inventaire du NCSC-NL recensait 968 de ces produits le 9 novembre 2026 : 205 corrigés, 215 vulnérables, 93 en cours d'analyse, 240 dépendants de l'environnement d'exécution et 214 non affectés. Vérifiez ces produits séparément et appliquez les mises à jour des fournisseurs dès qu'elles sont disponibles.
Assurez-vous que le correctif tourne vraiment. Sur les hôtes et les VM, un processus PHP-FPM, php-cgi ou Apache démarré avant la mise à niveau exécute toujours l'ancien code. Sa carte mémoire montre alors le binaire remplacé ou libphp comme supprimé. Comparez aussi l'heure de démarrage des processus avec l'heure de la mise à niveau :
for pid in $(pgrep -f 'php-fpm|php-cgi|apache2|httpd|frankenphp'); do
grep -qE '(php|libphp)[^/]*\(deleted\)' "/proc/$pid/maps" 2>/dev/null \
&& echo "PID $pid still runs a replaced PHP"
done
ps -o pid,lstart,args -p "$(pgrep -d, -f 'php-fpm|php-cgi|apache2|httpd|frankenphp')"
Indicateurs issus des sources primaires :
- Requêtes : des requêtes POST d'envoi de formulaire contenant la chaîne
PHP_SESSION_UPLOAD_PROGRESS, qu'Amazon Threat Intelligence a observée dans des tentatives d'exploitation. Amazon liste aussi des adresses sources (103.216.220.92,31.223.184.166,37.19.200.5,134.209.159.64,103.114.163.188,95.217.98.37) mais précise qu'elles appartiennent à une infrastructure d'anonymisation partagée : examinez une correspondance, ne la traitez pas comme une preuve. - Processus et fichiers : des processus worker PHP qui lancent des shells ou téléchargent des outils (CISA, qui a ajouté une règle de détection Sigma le 23 octobre), et des exécutions de processus ou modifications de fichiers inattendues sur les serveurs web (Amazon).
- Journaux : dans les journaux d'Apache, de PHP-FPM, des reverse proxies et des services, des avertissements ou erreurs core répétés avant l'exécution des scripts, des erreurs fatales et des erreurs d'analyse, et
Maximum execution time exceeded. L'avis de PHP ajoute que « l'absence d'erreur dans les journaux n'est pas une preuve de sécurité ».
Quand supposer une compromission. Si vous trouvez l'un de ces indicateurs, ou si un serveur exposé a fait tourner un PHP affecté sans atténuations et que vos journaux ne permettent pas d'exclure une exploitation, considérez-le comme compromis. PHP décrit l'impact comme une exécution de code à distance sous le compte du worker web, et ce compte peut généralement lire la configuration et les secrets de l'application.
Renouvelez ce que le worker pouvait lire. Mots de passe de bases de données, clés d'API et tokens dans les variables d'environnement et les fichiers de configuration, clés qui signent les sessions ou les cookies (et les sessions signées avec elles), et tous les identifiants cloud accessibles à l'hôte. Renouvelez-les après la reconstruction de l'hôte, afin que les nouveaux secrets ne se trouvent jamais sur une machine compromise.
Reconstruire plutôt que nettoyer. Remplacez un hôte ou un conteneur compromis à partir d'une image saine connue, et ne reprenez pas les fichiers que le worker pouvait écrire, comme les répertoires d'envoi, les caches ou le code généré. Ne réutilisez pas les images, caches de build ou artefacts produits sur un hôte compromis.
Que dire à vos clients
Si vous livrez un logiciel qui tourne sur PHP, vos clients vous poseront la question. Répondez avec des versions et des actions, même avant d'avoir toutes les réponses. Une réponse à adapter :
PHP2Shell (CVE-2026-109618, CVE-2026-109619) affecte les versions de PHP antérieures à 8.5.12, 8.4.27, 8.3.36 et 8.2.35, ainsi que toutes les branches PHP plus anciennes. Les versions [x à y] de [Produit] embarquent PHP [version] et sont affectées ; la version [z], publiée le [date], embarque PHP [version corrigée]. Veuillez passer à [z]. Si vous ne pouvez pas mettre à niveau tout de suite, appliquez les paramètres PHP de notre avis [lien] et limitez l'accès réseau à l'application. Les versions [a à b] de [Produit] ne sont pas affectées. Nous mettrons à jour cet avis d'ici le [date].
Si vous êtes encore en train de vérifier, dites-le, et dites quand vous répondrez. Pour une première déclaration et des modèles pour chaque cas de figure, consultez comment répondre aux clients après une attaque de la chaîne d'approvisionnement.
Comment CRACI vous aide
CRACI exécute vos jobs GitHub Actions et enregistre ce que chaque job intègre pendant le build, y compris les images de conteneurs, les paquets apt et apk et les paquets Composer, et il conserve chaque build passé avec sa SBOM. Lorsqu'une CVE est publiée, la réévaluation continue signale les builds passés qui contenaient le paquet affecté : vous voyez quelles versions ont été exposées et pendant combien de temps, pas seulement ce que trouve l'analyse du jour. Les policy gates peuvent bloquer les builds qui contiennent une CVE donnée.
Une limite pour cet incident : un PHP compilé dans une image php: officielle arrive à l'intérieur de l'image, pas sous forme de téléchargement de paquet. CRACI enregistre la référence d'image que chaque build a récupérée : cherchez donc dans vos builds les tags php: aussi bien que les paquets PHP.
Trouvez chaque build qui a livré un PHP vulnérable
Pour en savoir plus sur les traces de build : SBOM au moment du build, SBOM d'images Docker, ce que l'analyse de conteneurs ne voit pas, le catalogue CISA KEV et les tendances de publication des CVE. Autres incidents : toutes les vulnérabilités.
Pour la sécurité PHP au-delà de cet incident, consultez notre guide de sécurité PHP.
Sources et mises à jour
Sources primaires :
- PHP : avis de sécurité du 21 octobre 2026, avis informatif du 23 octobre 2026, GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp, versions prises en charge
- Enregistrements CVE : CVE-2026-109618, CVE-2026-109619
- CISA : alerte du 21 octobre 2026, catalogue KEV
- NCSC-NL : dépôt php2shell
- NVD : CVE-2026-109618, CVE-2026-109619
- FIRST : scores EPSS
Recherche et analyses :
- Calif: PHP2Shell, a tale of two PHP remote vulnerabilities
- Amazon Threat Intelligence
- watchTowr
- Akamai
- CybelAngel
- php2shell-scanner de Searchlight Cyber
Mises à jour :
- 2026-11-11: Ajout dans l'encadré des scores du NVD, de l'EPSS, des classes CWE, des crédits, des dernières versions sûres et des dates de fin de vie, ainsi que de PHP 8.6.0 RC4 et de sections sur le fonctionnement des bogues, la vérification du correctif et la recherche d'une compromission.
- 2026-11-11: Première publication.