PHP2Shell : deux failles critiques ouvrent l'exécution de code à distance sur PHP
Kévin GUIOT · 2026-10-21 · 8 min · Sécurité
Deux vulnérabilités critiques (CVE-2026-109618 et CVE-2026-109619), regroupées sous le nom PHP2Shell, permettent l'exécution de code à distance sans authentification sur quasiment toutes les versions de PHP. Analyse des mécanismes, versions corrigées et mesures à prendre.
PHP2Shell : deux failles critiques ouvrent l'exécution de code à distance sur PHP
Ce qui vient de se passer
Le 21 octobre 2026, l'équipe PHP publiait les versions 8.2.35, 8.3.36, 8.4.27 et 8.5.12. Pas une release de routine : ces versions corrigent deux failles critiques d'exécution de code à distance — CVE-2026-109618 et CVE-2026-109619, collectivement surnommées PHP2Shell par la presse technique.
CVSS 9,2 chacune. Exploitable à distance. Sans authentification. Et les PoC fournis dans les advisories visent directement Apache + mod_php en configuration par défaut — c'est-à-dire des millions de serveurs dans le monde.
Le point marquant — et ce que beaucoup de médias ont souligné — c'est que la faille s'exploite sans authentification ni même accès à l'application. Une simple requête HTTP vers un site suffit. C'est le premier cas complet documenté dans l'histoire moderne de PHP.
En pratique, la première question est « mon serveur tourne-t-il sous PHP, et en quelle version ? » — et la réponse tient souvent en une seconde : un test de la version PHP de votre site lit les indices publics que le serveur laisse aux visiteurs.
« Ce ne sont pas des bugs dans votre site : c'est le moteur PHP lui-même qui est attaquable, avant même l'exécution de votre code. »
CVE-2026-109618 : la corruption mémoire par OOM
Root cause. Quand PHP atteint sa limite mémoire (memory_limit), il effectue un longjmp() pour abandonner la requête. Or dans certains contextes, la mémoire de requête est atteignable avant d'être complètement initialisée : si une allocation échoue à ce moment précis, le longjmp laisse la mémoire dans un état invalide, et la procédure de shutdown la lit puis branche dessus — corruption, puis exécution de code.
Le déclencheur sans authentification. Le parsing multipart (RFC 1867, les formulaires avec upload) permet d'atteindre l'OOM tout en restant dans les limites apparentes : une requête multipart sans Content-Length exploitable passe le contrôle post_max_size tout en continuant à alimenter le body décodé ; le nombre de headers par part est illimité, ce qui fait exploser la mémoire interne par rapport à la taille réseau ; les contrôles de fichiers vides ne comptent pas dans max_file_uploads mais créent quand même les tableaux associés.
Sensibilité par SAPI. mod_php est confirmé exploitable : il invoque le shutdown même si le startup a échoué, et l'exploit a été démontré sur une configuration prefork standard. FrankenPHP est probablement dans le même cas. PHP-FPM tue le worker si le startup échoue — susceptible via des chemins applicatifs, mais sans exploit complet démontré. LSAPI se comporte comme FPM.
Le correctif. Suppression pure et simple du longjmp OOM : OOM gracieux au prochain safe point de la VM, puis _exit() brutal au-delà d'un second seuil.
CVE-2026-109619 : l'état global qui survit entre deux requêtes
Root cause. Les workers PHP conservent des états globaux (erreurs, session, objets, extensions) qui pointent vers la mémoire d'une requête. Si cet état n'est pas réinitialisé avant la libération du heap de requête, les opérations qui s'exécutent avant l'initialisation de la requête suivante consomment un pointeur périmé — use-after-free, exploitable par heap grooming.
Le modèle producer → consumer, souvent sur deux requêtes successives du même worker : une fatal error (parse error, require qui échoue, Maximum execution time exceeded, OOM) abandonne le reset et laisse l'état stale ; puis un consumer le lit avant que la requête suivante soit prête.
Deux consumers confirmés :
- Les diagnostics INI exécutés avant
php_request_startup():.htaccess/php_valuesous mod_php, ou les paramètresPHP_VALUE/PHP_ADMIN_VALUEtransmis par nginx ou mod_proxy_fcgi sous FPM. Une simple deprecation (auto_detect_line_endings,filter.default,mbstring.http_input…) suffit — etdisplay_errors=Offouerror_reportingne protègent pas : l'état est lu avant la décision de reporting. - Le suivi d'upload de session (
session.upload_progress), activé par défaut, qui atteint le code session avant l'initialisation —session_start()n'est même pas requis.
Qui est concerné
- Tout site web exécutant PHP 8.2 avant 8.2.35, 8.3 avant 8.3.36, 8.4 avant 8.4.27 ou 8.5 avant 8.5.12
- Toutes les versions encore plus anciennes : PHP 5, 7, 8.0 et 8.1 sont en fin de vie et ne recevront jamais le correctif officiel
- Sites en hébergement mutualisé, WordPress, PrestaShop, applications métier Laravel ou Symfony, sites vitrines et vieux CMS
- L'attaquant n'a besoin que de pouvoir envoyer une requête HTTP au serveur — pas d'accès à l'application, pas d'accès admin
Pourquoi la simple mitigation ne suffit pas
Les réglages de contournement existent mais aucun ne ferme réellement la porte :
memory_limit=-1casse le déclencheur OOM prévisible de la première faille — incompletfatal_error_backtraces=0(PHP 8.5) etsession.upload_progress.enabled=0retirent des consumers de la seconde — mais n'importe quelle extension peut publier ou consommer du stale statepm.max_requests=1empêche le chaînage entre requêtes d'un même worker — au prix des performances- Bloquer le multipart au niveau du frontend aide si les uploads sont inutilisés
RLIMIT_AS et RLIMIT_DATA provoquent précisément le chemin longjmp vulnérable — ne les utilisez pas comme palliatif. Ce qu'il faut faire maintenant
- Inventorier : pour chaque serveur, la version PHP et le SAPI (mod_php vs FPM vs FrankenPHP). Le risque diffère selon le SAPI, mais tous les chemins exposés doivent être couverts.
- Patcher : passer en 8.2.35, 8.3.36, 8.4.27 ou 8.5.12 selon votre branche — les paquets Debian/Ubuntu, RHEL et les images Docker officielles sont déjà à jour.
- Migrer les versions EOL : si vous tournez en 7.4, 8.0 ou 8.1, aucun patch officiel n'arrivera. C'est le cas le plus urgent — et le plus fréquent en production.
- Vérifier les extensions : une mise à jour PHP peut toucher plusieurs sites et certaines extensions doivent être contrôlées avant la bascule.
En synthèse
- Deux failles RCE non authentifiées ont été publiées le 21 octobre 2026 dans PHP — un cas sans précédent dans l'histoire récente du langage.
- Pratiquement toutes les versions PHP en production sont concernées ; seuls les patchs sortis aujourd'hui (8.2.35 à 8.5.12) corrigent réellement.
- La mitigation par configuration est incomplète — surtout pour la seconde faille, où n'importe quelle extension peut republier du stale state.
- Si vous exploitez PHP en production, l'heure est à la mise à jour. Pas la semaine prochaine : maintenant — vérifiez votre version PHP en 10 secondes.