PHP2Shell : bien corriger PHP et le durcir avant la prochaine faille critique
Publié: · 19 min de lecture · Par Oluniyi D. Ajao
Le 21 octobre 2026, le projet PHP a publié des versions correctives pour deux failles critiques qui touchent PHP lui-même : CVE-2026-109618 et CVE-2026-109619. Toutes deux peuvent permettre à un attaquant non authentifié d'exécuter du code sur un serveur au moyen de requêtes web forgées. Cinq jours plus tard, l'agence américaine de cybersécurité CISA (Cybersecurity and Infrastructure Security Agency) les a ajoutées à son catalogue des vulnérabilités dont l'exploitation dans des attaques est avérée. Les versions corrigées sont PHP 8.5.12, 8.4.27, 8.3.36 et 8.2.35.
La presse spécialisée en sécurité a baptisé ce duo « PHP2Shell ». Ce guide explique simplement en quoi consistent les deux bugs, puis donne aux développeurs et aux administrateurs système les vérifications précises à effectuer : quel PHP sert réellement votre site, si votre distribution a rétroporté le correctif, comment faire en sorte que la mise à jour prenne effet, et que faire si vous ne pouvez pas mettre à jour aujourd'hui. Il va ensuite plus loin que le correctif. PHP2Shell ne sera pas la dernière faille critique de PHP, et la dernière partie de ce guide porte sur le durcissement qui limite ce qu'un attaquant peut faire lorsque la prochaine faille arrive avant votre mise à jour.

PHP2Shell, de quoi s'agit-il ?
« PHP2Shell » n'est pas un nom officiel. Le projet PHP, ses avis de sécurité sur GitHub, les fiches CVE et la CISA s'en tiennent aux numéros CVE et à des intitulés descriptifs. Le surnom vient de la presse spécialisée, et il décrit le résultat : une requête forgée envoyée à PHP qui se termine par un shell sur le serveur.
L'avis de sécurité du projet PHP décrit ainsi les deux bugs :
« RCE par corruption lors d'un épuisement de la mémoire (OOM), CVE-2026-109618 : la gestion de l'épuisement de la 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 ces données invalides comme valides. »
« RCE par état global obsolète, CVE-2026-109619 : un état interne propre à une requête peut survivre à la libération de la mémoire sur laquelle il repose. Une requête ultérieure traitée par le même worker peut utiliser cet état obsolète avant que l'initialisation normale ne le réinitialise. »
En pratique :
- CVE-2026-109618 passe par l'analyse des envois de formulaires multipart dans PHP. Une requête conçue pour épuiser la mémoire de PHP au mauvais moment laisse des données internes à moitié construites, et le nettoyage qui suit leur fait confiance.
- CVE-2026-109619 est une utilisation de mémoire après libération (use-after-free) d'une requête à l'autre. Un worker PHP qui sert une requête peut conserver un pointeur vers une zone mémoire déjà libérée, et une requête ultérieure sur ce même worker s'en sert. L'un des chemins confirmés passe par le suivi de progression des envois en session (session upload progress), activé par défaut et qui, selon les termes de l'avis GitHub, ne nécessite « aucun appel à
session_start()de la part de l'application ».
L'équipe de sécurité de PHP attribue à chacune un score CVSS v4.0 de 9,2 sur 10 (critique). Le détail décisif tient à leur emplacement : elles se trouvent dans l'environnement d'exécution de PHP lui-même et, sur Apache avec mod_php, elles peuvent être déclenchées avant l'exécution du moindre code applicatif. Mettre à jour Laravel, Symfony, WordPress ou vos paquets Composer ne corrige pas PHP2Shell. C'est le binaire PHP qui doit changer.
Qui est exposé ?
L'avis du projet PHP est sans détour : « toutes les installations PHP qui servent des requêtes web, y compris PHP-FPM, Apache avec mod_php, php-cgi, FrankenPHP et LiteSpeed ». Il juge le risque le plus élevé pour Apache avec mod_php, « avec un exploit démontré dans lequel une requête non authentifiée peut déclencher l'attaque avant l'exécution du moindre code applicatif ».
Les avis GitHub précisent la situation selon la configuration. L'exécution de code à distance complète via le bug mémoire a été validée sur mod_php avec les limites de mémoire et d'entrée par défaut. PHP-FPM est jugé vulnérable d'après l'analyse du code source, et le chemin du second bug qui passe par les sessions a été validé sur mod_php comme sur FPM. FrankenPHP est décrit comme probablement vulnérable aux attaques qui ne dépendent pas de l'application ; pour l'interface de LiteSpeed, des exploits propres à l'application sont jugés probables mais non validés. Si votre serveur exécute PHP pour le web de l'une de ces façons et ne tourne pas sur une version corrigée, considérez-le comme vulnérable.
Versions concernées, selon les avis : toutes les versions 8.2 antérieures à 8.2.35, toutes les 8.3 antérieures à 8.3.36, toutes les 8.4 antérieures à 8.4.27 et toutes les 8.5 antérieures à 8.5.12. PHP 8.1 et les versions plus anciennes ne reçoivent plus de nouvelles versions du projet PHP : « Certaines distributions et certains fournisseurs de support LTS proposent des correctifs rétroportés, contactez donc votre fournisseur pour plus de détails, ou passez à une version prise en charge. » Le projet a également publié des rétroportages minimaux du code source pour 7.4, 8.0 et 8.1, qui sont des correctifs et non des versions. À noter aussi : PHP 8.2 arrive en fin de vie le 31 décembre 2026, si bien qu'un serveur passé en 8.2.35 aujourd'hui a de toute façon besoin d'un plan de migration.
Ces failles sont-elles exploitées ?
Oui. La CISA a ajouté les deux CVE à son catalogue KEV (Known Exploited Vulnerabilities) le 26 octobre 2026. Le même jour, BleepingComputer rapportait que des honeypots gérés par Adel Karimi, responsable détection et réponse chez Perplexity, avaient enregistré une exécution de code à distance confirmée contre un serveur Apache mod_php sous PHP 8.4.26, soit une version de retard sur le correctif, et qu'Amazon Threat Intelligence avait repéré des attaquants ciblant ces failles quatre jours avant la publication des correctifs. Arctic Wolf a signalé des scans à grande échelle peu après la divulgation.
Des preuves de concept ont fuité avant les correctifs. L'équipe de sécurité de PHP a assuré à BleepingComputer qu'aucune n'était fonctionnelle, mais les attaques confirmées montrent que des exploits fonctionnels existent. Partez du principe que des scanners automatisés testent déjà chaque point d'entrée PHP public qu'ils parviennent à trouver.
Côté développeurs : ce qu'il faut vérifier
- Vérifiez le PHP qui sert le web, pas celui de votre terminal.
php -vrenvoie la version du binaire en ligne de commande. Votre site peut tourner sur un autre binaire PHP, via FPM, Apache ou un panneau d'hébergement. Placez sur le site une page temporaire qui affichePHP_VERSIONetPHP_SAPI, chargez-la, puis supprimez-la. - Reconstruisez vos conteneurs. Si vous déployez PHP avec Docker, le correctif se trouve dans l'image de base. Reconstruisez avec
docker build --pullsur une base qui embarque une version corrigée, redéployez, et vérifiez que le conteneur en cours d'exécution affiche bien cette version. - Mettre à jour votre application ne vous protège pas. Les mises à jour du framework ou du CMS restent utiles, mais les failles se trouvent dans PHP. Si vous hésitez sur où héberger WordPress, la question qui compte ici est de savoir qui corrige PHP et le redémarre, et en combien de temps.
- Sur un hébergement mutualisé ou infogéré, interrogez votre hébergeur. Demandez-lui quelle version de PHP fait tourner votre site et si les workers ont été redémarrés après la mise à jour. Les deux questions comptent.
Côté administrateurs système : le correctif, étape par étape
1. Repérez chaque PHP qui sert du trafic web
Un serveur héberge souvent plusieurs installations de PHP côte à côte : les paquets de la distribution, un dépôt tiers, les versions compilées par un panneau de contrôle, un conteneur. Recensez-les toutes, puis identifiez celle qu'utilise réellement chaque site. Pour PHP-FPM, listez chaque processus maître et le binaire qui se trouve derrière :
pgrep -af 'php-fpm: master'
for p in $(pgrep -f 'php-fpm: master'); do sudo readlink /proc/$p/exe; done
Si un chemin se termine par « (deleted) », le paquet a été remplacé sur le disque mais ce processus n'a jamais été redémarré : il exécute donc toujours l'ancien code.
Avec Apache et mod_php, le module fait partie du processus Apache lui-même : c'est donc le paquet PHP installé qu'il faut vérifier.
2. Lisez correctement le numéro de version
Les distributions rétroportent souvent les correctifs de sécurité sans changer le numéro de version amont, et c'est l'une des raisons pour lesquelles le choix de la distribution compte (voir notre guide pour choisir le système d'exploitation de votre VPS). Ubuntu 24.04, par exemple, a corrigé les deux CVE dans le paquet 8.3.6-0ubuntu0.24.04.13 : toujours « 8.3.6 », mais corrigé. Une version inférieure à 8.3.36 sur un paquet de distribution ne signifie donc pas à elle seule que vous êtes vulnérable. C'est le suivi de sécurité de votre éditeur ou le journal des modifications du paquet qui tranche :
# Debian / Ubuntu
zgrep -cE 'CVE-2026-10961[89]' /usr/share/doc/php*-fpm/changelog.Debian.gz
# Paquets des distributions de la famille RHEL
rpm -q --changelog php-fpm | grep -cE 'CVE-2026-10961[89]'
Un résultat supérieur à zéro signifie que le paquet intègre les correctifs. Les paquets qui suivent la numérotation amont, comme ceux des dépôts tiers, des panneaux de contrôle ou les images Docker officielles, ne mentionnent souvent aucun numéro de CVE : pour eux, un zéro ne veut rien dire, et c'est la version elle-même qui fait foi. Les outils publics de suivi de sécurité de Debian et d'Ubuntu indiquent la version corrigée du paquet pour chaque version de la distribution.
3. Mettez à jour, puis redémarrez chaque worker
Installer le paquet ne modifie pas les processus en cours d'exécution. Les workers PHP-FPM et les processus enfants d'Apache gardent l'ancien code en mémoire tant qu'ils ne sont pas redémarrés. Après la mise à jour, redémarrez complètement le service :
systemctl restart php8.3-fpm # ou php-fpm, selon votre distribution
systemctl restart apache2 # ou httpd, si vous utilisez mod_php
Vérifiez ensuite que la mise à jour est bien prise en compte. L'heure de démarrage du service doit être postérieure à l'heure d'installation du paquet :
systemctl show php8.3-fpm -p ActiveEnterTimestamp
rpm -q --last php-fpm # famille RHEL
zgrep -h " upgrade .*php" /var/log/dpkg.log* | sort | tail # Debian / Ubuntu
4. Traitez le cas des versions de PHP en fin de vie
Les serveurs sous PHP 8.1 ou plus ancien ont trois options : un rétroportage de l'éditeur (certaines distributions et certains fournisseurs de support à long terme en proposent), les correctifs minimaux du code source publiés par le projet PHP pour 7.4, 8.0 et 8.1 si vous compilez PHP vous-même, ou une migration vers une branche prise en charge. Des trois, la migration est la seule qui couvre aussi la prochaine faille critique.
5. Si vous ne pouvez pas mettre à jour aujourd'hui
Le projet PHP est formel, il n'existe pas de solution de contournement complète : « Il n'existe aucune mesure d'atténuation complète, la mise à jour est le seul choix sûr. » Il énumère toutefois des mesures qui ferment certains chemins d'attaque précis, le temps de planifier la mise à jour. Définissez-les dans la configuration du pool FPM ou d'Apache, jamais avec ini_set() ou .user.ini, et redémarrez ensuite chaque worker :
- Pour CVE-2026-109619 :
session.upload_progress.enabled=0, qui bloque les chemins confirmés passant par les sessions. Sous PHP 8.5, ajoutez aussifatal_error_backtraces=0. - Pour CVE-2026-109618 :
memory_limit=-1, imposé au niveau administrateur. Ce réglage supprime le plafond de mémoire propre à PHP : associez-le donc à une limite mémoire au niveau du conteneur ou du cgroup. L'avis GitHub met en garde contreRLIMIT_ASouRLIMIT_DATA, qui déclenchent le chemin vulnérable. Le projet PHP recommande aussi des limites basses sur la taille des requêtes :post_max_sizeautour de 8M si vous ne recevez pas de fichiers, 32M si vous en recevez.
Dans un fichier de pool PHP-FPM :
php_admin_value[session.upload_progress.enabled] = 0
php_admin_value[memory_limit] = -1
Dans la configuration d'Apache, pour mod_php :
php_admin_flag session.upload_progress.enabled off
php_admin_value memory_limit -1
6. Partez du principe qu'un serveur exposé a pu être sondé
Si un serveur exposé à Internet a fait tourner un PHP vulnérable depuis la mi-octobre, le correctif ferme la porte mais ne dit rien de qui est entré avant. La fiche du catalogue de la CISA oriente les agences fédérales américaines vers une première analyse forensique, et c'est un niveau d'exigence raisonnable pour tout le monde : examinez les journaux web et les journaux d'erreurs PHP à la recherche de requêtes POST multipart inhabituelles et de plantages de workers, cherchez des fichiers et des processus appartenant à l'utilisateur web que vous n'avez pas créés, et renouvelez les identifiants que l'utilisateur web pouvait lire.
Au-delà du correctif : durcir PHP pour la prochaine faille
Le correctif règle cette faille-ci. Il ne règle pas la suivante, qui pourrait être exploitée avant même qu'un correctif existe. Les mesures ci-dessous n'empêchent pas une faille de PHP d'être déclenchée. Elles déterminent ce que l'attaquant obtient quand elle l'est : les fichiers d'un seul site, ou le serveur tout entier, ses identifiants et tout ce qu'il peut atteindre.
Donnez à chaque site son propre utilisateur PHP non privilégié
Faites tourner chaque site dans son propre pool PHP-FPM, sous son propre utilisateur système, et jamais en root. Une exécution de code « en tant qu'utilisateur du worker web », pour reprendre les termes de l'avis GitHub, devient alors une exécution sous l'utilisateur d'un seul site, et non sous l'utilisateur capable de lire tous les sites du serveur :
[site1]
user = site1
group = site1
listen = /run/php/site1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
Sur la famille RHEL, utilisez /run/php-fpm/site1.sock et listen.owner = nginx (ou apache). Fermez le répertoire de chaque site aux autres (mode 750), faute de quoi les utilisateurs de chaque site pourront toujours lire les fichiers des autres.
Passez le code en lecture seule, et n'exécutez jamais les fichiers envoyés
L'utilisateur PHP doit pouvoir lire l'application, mais pas la modifier. Confiez la propriété du code à un utilisateur de déploiement distinct, et ne donnez à l'utilisateur PHP un accès en écriture qu'aux répertoires qui en ont besoin, comme ceux des uploads et du cache. Un worker qui ne peut pas écrire dans l'arborescence du code ne peut pas réécrire votre application. Il peut en revanche déposer des fichiers dans les répertoires accessibles en écriture, modifier la base de données ou rester résident dans un worker en cours d'exécution : considérez donc chaque chemin accessible en écriture comme non fiable, n'y incluez jamais de PHP, et redémarrez les workers après un incident. Interdisez ensuite l'exécution de PHP depuis ces répertoires. Dans nginx, placez ceci au-dessus de votre bloc location PHP principal :
location ~* ^/(?:uploads|wp-content/uploads)/.*\.(?:php\d*|phtml|phar)(?:/|$) {
deny all;
}
Avec mod_php, placez php_admin_flag engine off dans un bloc <Directory> visant le répertoire d'upload.
Réduisez la surface exposée par le serveur
- Supprimez les versions et extensions de PHP qu'aucun site n'utilise. Chaque version installée est une version de plus à corriger.
- Définissez
expose_php = Offpour que les réponses n'affichent pas votre version exacte de PHP aux scanners. - Supprimez toute page
phpinfo(). - Limitez la taille des requêtes en amont de PHP, au niveau du serveur web ou du proxy (
client_max_body_sizedans nginx). Les recommandations du projet PHP pour CVE-2026-109618 prévoient elles-mêmes des limites sur la taille décodée, le nombre de champs et le nombre de parties avant que les requêtes n'atteignent PHP. Limiter le nombre de champs et de parties exige une règle sur un proxy ou un WAF ; si vous ne recevez aucun fichier par formulaire, bloquez-y les requêtes multipart.
Restreignez ce que PHP peut joindre
Une bonne partie de ce que fait un attaquant une fois entré exige une connexion sortante : télécharger une charge utile, ouvrir un reverse shell, exfiltrer des données volées. La plupart des workers web n'ont jamais besoin de joindre autre chose qu'une base de données, un cache et quelques API connues. systemd peut imposer cette restriction au service PHP-FPM, et rendre du même coup les répertoires système accessibles en lecture seule pour lui. Lancez systemctl edit php8.3-fpm (ou php-fpm) et ajoutez :
[Service]
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
IPAddressDeny=any
IPAddressAllow=localhost 10.0.0.0/8
Adaptez IPAddressAllow à ce dont PHP a réellement besoin. Ces règles ne filtrent que des adresses IP : la résolution DNS échoue si votre résolveur n'est ni local (127.0.0.53 sous Ubuntu) ni autorisé, les API externes demandent d'autoriser leurs adresses ou de passer par un proxy sortant, et FPM en TCP derrière un proxy distant demande d'autoriser ce proxy. NoNewPrivileges bloque aussi l'utilitaire setgid dont Postfix se sert pour mail() : envoyez donc les e-mails en SMTP vers un relais autorisé. N'appliquez ces règles qu'à PHP-FPM, jamais à apache2, httpd ou nginx. Testez en préproduction, redémarrez, puis vérifiez que PHP ne peut pas joindre une adresse extérieure et que le site fonctionne toujours.
Limitez et cloisonnez les secrets
Partez du principe que tout ce que l'utilisateur PHP peut lire sera lu. Donnez à chaque site un compte de base de données doté des seuls privilèges dont l'application a besoin, placez les fichiers de configuration qui contiennent des identifiants hors de la racine web, lisibles uniquement par l'utilisateur du site, et ne laissez pas sur un serveur web des clés dont il n'a pas l'usage, comme des identifiants de sauvegarde ou des jetons de fournisseur cloud. Une intrusion coûte alors les données d'une seule base, et non toute votre infrastructure.
Raccourcissez le délai de correction
Avec PHP2Shell, quelques jours ont suffi entre le correctif et les attaques confirmées. Abonnez-vous aux annonces du projet PHP et à la liste de sécurité de votre distribution. Activez les mises à jour de sécurité automatiques (unattended-upgrades sur Debian et Ubuntu, dnf-automatic avec apply_updates = yes sur la famille RHEL). Vérifiez qu'elles couvrent le dépôt d'où provient votre PHP : sur Debian et Ubuntu, les dépôts PHP tiers ne sont pas inclus par défaut. Associez-les à une vérification des services qui exécutent encore l'ancien code : needrestart sur Debian et Ubuntu, dnf needs-restarting -s sur la famille RHEL. Tant qu'une mise à jour installée n'a pas été suivie d'un redémarrage, le serveur continue d'exécuter le code vulnérable.
Détecter l'intrusion, et pouvoir s'en relever
- Envoyez les journaux web, PHP et système hors du serveur, pour qu'un attaquant qui y a pris pied ne puisse pas les effacer.
- Surveillez les modifications de l'arborescence du code avec un outil de contrôle d'intégrité des fichiers comme AIDE. Sur une arborescence en lecture seule, toute modification en dehors d'un déploiement est un signal d'alerte.
- Déclenchez une alerte quand l'utilisateur web lance des processus inhabituels pour lui, comme un shell interactif ou un outil de téléchargement. Établissez d'abord une référence : la fonction
mail()de PHP lanceshpour appeler sendmail. - Conservez des sauvegardes à un endroit où le serveur web ne peut ni écrire ni supprimer, et testez une restauration. Quand un serveur n'est plus digne de confiance, le reconstruire à partir d'une image propre et d'une sauvegarde saine va plus vite que le nettoyer.
Ne pas confondre avec CVE-2026-115560
Le 23 octobre, le projet PHP a publié un avis informatif distinct portant sur un problème moins probable lié au suivi de progression des envois en session, CVE-2026-115560, qui ne fait pas partie de PHP2Shell et n'a pas été corrigé dans les versions du 21 octobre. Il préconise le même réglage : « Nous vous suggérons de définir session.upload_progress.enabled=0 jusqu'à la prochaine version corrective régulière, afin de vous protéger complètement d'un vecteur de RCE peu probable. »
La liste de vérification
Pour PHP2Shell, dès maintenant :
- Recensez chaque installation de PHP présente sur le serveur, et celle qui sert chaque site.
- Vérifiez que chacune est en 8.5.12, 8.4.27, 8.3.36, 8.2.35 ou sur un paquet de l'éditeur qui intègre les correctifs.
- Redémarrez chaque pool FPM et chaque instance Apache, et comparez l'heure de démarrage à l'heure d'installation.
- Reconstruisez et redéployez les conteneurs à partir d'images de base corrigées.
- Planifiez dès maintenant l'abandon de PHP 8.1 et des versions antérieures, et celui de la 8.2 avant le 31 décembre 2026.
- Définissez
session.upload_progress.enabled=0si vous n'utilisez pas le suivi de progression des envois. - Examinez les journaux de tout serveur exposé depuis la mi-octobre.
Pour la prochaine faille :
- Un pool PHP-FPM et un utilisateur non privilégié par site, jamais root.
- Code appartenant à un utilisateur de déploiement, en lecture seule pour PHP ; aucune exécution de PHP dans les répertoires d'upload.
- Installations et extensions PHP inutilisées supprimées,
expose_php = Off, taille des requêtes limitée en amont de PHP. - Connexions sortantes de PHP limitées à ce dont l'application a besoin.
- Comptes de base de données aux privilèges minimaux, et aucune clé oubliée sur le serveur web.
- Mises à jour de sécurité automatiques, doublées d'une vérification des redémarrages.
- Journaux hors du serveur, alertes d'intégrité des fichiers, et sauvegardes testées hors de portée du serveur web.
Sur un serveur autogéré, chacune de ces étapes vous revient. Les Serveurs Cloud AFRICLOUD sont fournis avec un accès root complet : la version de PHP, sa mise à jour et son redémarrage sont entre vos mains.
Sources
- Projet PHP : avis de sécurité et annonces de versions, du 20 au 23 octobre 2026
- Avis de sécurité PHP sur GitHub : GHSA-w8hw-w9fx-j79w (CVE-2026-109618) et GHSA-6wmf-4rv5-p3rp (CVE-2026-109619)
- NVD : CVE-2026-109618 et CVE-2026-109619
- CISA : ajout de deux vulnérabilités exploitées au catalogue, 26 octobre 2026
- Manuel PHP : configuration des sessions à l'exécution
- Ubuntu : CVE-2026-109618 ; Debian : suivi de sécurité
- BleepingComputer : les failles PHP2Shell activement exploitées ; Arctic Wolf : analyse de PHP2Shell