Aller au contenu

Journal · 22 octobre 2026

php2shell : pourquoi la faille PHP de cette semaine ne nous a pas réveillés

Le 21 octobre, PHP a publié en urgence le correctif de deux failles qui permettent d'exécuter du code sur un serveur sans compte. Nous n'avions rien à patcher : nos produits n'utilisent pas PHP. Mais ce n'est pas ce qui nous protège le mieux.

Ce qui s'est passé

Le 21 octobre 2026, l'équipe sécurité de PHP a publié les versions 8.5.12, 8.4.27, 8.3.36 et 8.2.35 pour corriger deux failles surnommées « php2shell » (CVE-2026-109618 et CVE-2026-109619), notées 9,2 en CVSS 4.0. Toutes deux permettent à un inconnu d'exécuter du code sur le serveur avec une simple requête HTTP, sans compte. La page de connexion n'y change rien : PHP traite la requête piégée avant que la moindre ligne de l'application ne s'exécute.

La première tient à la façon dont PHP fait respecter sa limite de mémoire. Quand une requête la dépasse, au milieu de l'analyse d'un formulaire d'envoi de fichier par exemple, PHP s'interrompt net et laisse derrière lui des données à moitié construites, que la routine de nettoyage traite ensuite comme valides. La seconde laisse survivre l'état d'une requête après que sa mémoire a été libérée : la requête suivante servie par le même processus, celle d'un autre visiteur, peut tomber dessus. Le suivi de progression des envois, actif par défaut, suffit à l'atteindre.

Tout ce qui sert du PHP sur le web est concerné : mod_php sous Apache, PHP-FPM, php-cgi, FrankenPHP, LiteSpeed. Le chemin de code fautif remonte à PHP 5.4, sorti en 2012, et les branches 8.1 et plus anciennes n'ont reçu que des correctifs de source, sans version publiée. Les chercheurs de Calif ont confirmé l'exécution de code sans authentification sur des versions de WordPress, Drupal, Joomla et Magento. PHP fait tourner environ 69 % des sites dont on connaît le langage serveur.

Le calendrier s'est emballé. Les pots de miel d'Amazon ont vu une première tentative d'exploitation le 17 octobre, quatre jours avant la publication. Les identifiants des failles ont fuité le 20, et PHP a avancé son correctif d'un jour. Le 21, Amazon, Cloudflare et watchTowr signalaient des tentatives d'exploitation, venues de plusieurs acteurs ; la PHP Foundation, elle, n'avait identifié aucun exploit public fonctionnel au moment de la publication. L'équipe de PHP a fait son travail vite et bien. Ce texte n'est pas contre elle.

Pourquoi nous n'avions rien à patcher

D'abord parce qu'aucun de nos produits n'est écrit en PHP. Ce que le Lab exploite, ses produits comme les plateformes qu'il construit pour ses clients, tourne sur Elixir et la machine virtuelle d'Erlang, la BEAM ; nous avons expliqué pourquoi dans un article précédent. Mercredi, il n'y avait donc ni php.ini à durcir ni serveur à redémarrer dans l'urgence.

Il y a aussi une raison de fond, qu'il ne faut pas exagérer. La seconde faille vit d'un état qui passe d'une requête à la suivante dans le même processus. Sur la BEAM, chaque connexion est servie par son propre processus léger, avec sa propre mémoire, rendue quand il se termine : aucun processus ne garde ce que le visiteur précédent a laissé. Et un processus qui plante meurt seul, au lieu de continuer avec un état abîmé. Cette classe de bug y est beaucoup plus difficile à écrire.

Plus difficile, pas impossible. La BEAM est écrite en C, comme PHP, et notre écosystème a eu sa faille critique : en avril 2025, le serveur SSH d'Erlang/OTP permettait d'exécuter du code sans authentification (CVE-2025-32433, notée 10). Nos applications ne démarrent pas ce serveur, mais la leçon tient : le choix du langage nous a épargné celle-ci, il ne nous épargnera pas la suivante.

Ce qui nous protège vraiment : mettre à jour souvent

Une faille se corrige par une mise à jour. Tout tient donc dans la distance qui vous sépare de la version corrigée. Si vous êtes à jour, c'est un numéro de version qui change et un redémarrage. Si vous avez trois ans de retard, c'est une migration, avec ses régressions, et elle tombe le jour où un exploit circule. Les sites restés en PHP 8.1 le découvrent cette semaine : il n'existe pas de version corrigée pour eux.

Alors nous montons nos dépendances en continu, par petits pas. En cinq mois, le fichier qui fige les versions des dépendances de notre CMS et des sites qu'il sert a changé 24 fois. Chaque montée est petite, et donc sans histoire.

Et nous regardons. Récemment, l'audit de l'écosystème Elixir signalait 45 avis de sécurité sur 12 de nos paquets, dont neuf classés graves, parmi lesquels une faille XSS dans les formulaires de connexion par lien magique de notre bibliothèque d'authentification. Toutes les montées tenaient dans nos contraintes de version : un changement de numéros, sans rien réécrire. Quelques semaines plus tard, de nouveaux avis critiques sur la même bibliothèque, dont des liens magiques rejouables et une session révoquée encore acceptée : même traitement, même tranquillité.

Ce contrôle ne dépend pas de notre vigilance. Chaque modification passe un audit des dépendances et une analyse statique de sécurité, et la construction échoue si l'un des deux trouve quelque chose. Une fois par mois, le même audit tourne sans qu'aucune modification le déclenche, pour attraper les avis publiés entre deux livraisons, et une sonde vérifie le chiffrement et les en-têtes de sécurité des plateformes que nous hébergeons.

Rien d'héroïque là-dedans. C'est une routine, et c'est elle qui fait qu'une faille critique se traite comme un mardi ordinaire.

Si vous avez du PHP en production

Mettez à jour aujourd'hui : 8.5.12, 8.4.27, 8.3.36 ou 8.2.35. Faites l'inventaire du PHP qui sert le web, pas de celui de la ligne de commande, qui peut être une autre version, et n'oubliez ni les conteneurs ni les produits qui embarquent leur propre interpréteur. Le NCSC néerlandais tient une liste des produits concernés.

Si vous ne pouvez pas mettre à jour tout de suite, le CERT-EU recommande trois réglages, posés par l'administrateur pour que l'application ne puisse pas les contourner : dans le pool PHP-FPM, ou avec les mêmes directives dans la configuration Apache pour mod_php.

; pool PHP-FPM — pas ini_set(), pas .user.ini
php_admin_value[memory_limit] = -1
php_admin_flag[session.upload_progress.enabled] = off
; PHP 8.5 seulement
php_admin_flag[fatal_error_backtraces] = off

Compensez memory_limit = -1 par une limite de mémoire sur le conteneur, puis redémarrez tous les workers. Ce sont des rustines : Datadog rappelle que ce réglage bloque le chemin d'exploitation connu, pas le défaut lui-même.

Et si la mise à jour est impossible parce que l'application ne tourne que sur une version ancienne, c'est le vrai sujet, et il ne date pas de cette semaine. C'est le genre de chantier que nous menons : reprendre une application que plus personne n'ose toucher et la remettre sur une base qu'on peut mettre à jour un mardi. Écrivez-nous.