flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal
CVE-2026-87902 : traversée de chemin dans les modèles WordPress
Un nom de page décodé sans validation a été utilisé dans la résolution des modèles, permettant l’inclusion locale de PHP sans authentification et une RCE conditionnelle selon le thème et l’environnement.[1]
Imaginez une bibliothécaire qui vérifie chaque demande. WordPress contrôlait un chemin vers les modèles, mais pas celui créé à partir du nom décodé ; certains marqueurs pouvaient la faire sortir des rayons du thème. Le correctif valide le nom et maintient le modèle dans un répertoire autorisé.[1], [2], [3]
Concepts Clés et Termes
Résolution des modèles- WordPress ordonne des candidats PHP puis cherche le premier fichier correspondant dans le thème actif.[1], [2]
Traversée de chemin- Des éléments comme
..peuvent sortir du répertoire prévu si l’entrée n’est pas validée.[1] Inclusion locale de PHP- Chargement d’un fichier PHP déjà présent sur le serveur ; la RCE demande d’autres conditions.[1]
`validate_file()`- Fonction WordPress qui rejette les composants de chemin interdits avant leur utilisation.[3]
Correspondances de référentiels
- Référence CWE pour la faiblesse décrite dans ce guide : CWE-98
- CISA KEV — ajouté le 2026-09-25 — CVE-2026-87902
Analyse de Cause Racine
Dans get_page_template(), WordPress décodait pagename et ajoutait page-{name}.php sans validate_file(), contrairement à la branche voisine. Le chemin pouvait donc sortir du thème. Il faut un répertoire supérieur page-* et un fichier PHP local lisible ; la RCE exige aussi des conditions PHP/serveur supplémentaires. La version 7.1.2 valide la valeur décodée et limite le chemin résolu dans locate_template(). L’avis WordPress classe cette faiblesse CWE-98 (contrôle incorrect du nom de fichier utilisé dans un include/require PHP) et attribue la découverte et la divulgation responsable à Robert Ressl.[1], [2], [3], [7]
Périmètre de CVE-2026-87902 : exposition et RCE conditionnelle
| Condition de déploiement | Ce que confirment les sources primaires | Action à mener |
|---|---|---|
| Branche WordPress Core vulnérable | Le GHSA répertorie les versions vulnérables par branche, de 4.7.0–4.7.36 à 7.1.0–7.1.1. Les correctifs correspondants vont de 4.7.37 (rétroportage le plus ancien) à 7.1.2 (branche actuelle), avec une version corrigée propre à chaque branche indiquée. | Vérifiez la version installée et appliquez le correctif de la branche correspondante. Mettez à niveau les versions antérieures à 4.7 vers une version prise en charge. |
| Structure du thème actif | Le thème parent ou enfant actif doit contenir un répertoire de premier niveau dont le nom commence par page- (par exemple, page-templates). | Examinez les répertoires des deux thèmes actifs. Vérifiez à nouveau cette condition si le thème actif change. |
| Fichier PHP local lisible | Un fichier .php choisi doit exister hors des répertoires des thèmes actifs et être lisible par le compte du serveur web. | Vérifiez quels fichiers PHP locaux sont lisibles par le serveur web ; la seule plage de versions du CVE ne prouve pas qu’un fichier a été inclus. |
| Environnement de RCE conditionnelle | L’avis décrit une RCE uniquement si des conditions PHP/serveur supplémentaires sont réunies. Il cite notamment pearcmd.php avec register_argc_argv=On, l’image PHP officielle pour Docker et les configurations cPanel par défaut utilisant PHP avant 8.5. | Évaluez le runtime et la configuration PHP réels. Une version WordPress vulnérable ne suffit pas à établir une RCE ou une compromission. |
Déroulement de l'Attaque Étape par Étape
L’entrée atteint la sélection
Une requête non authentifiée fournit le nom utilisé pour créer des candidats ; aucun compte ni clic n’est nécessaire.[1]
La recherche sort de la racine
Avec un répertoire page-* et un PHP local lisible, le thème peut résoudre un fichier hors de son dossier.[1]
Impact conditionnel
La RCE dépend d’autres prérequis PHP/serveur ; la version seule ne prouve ni exploitabilité ni intrusion.[1]
Code Source : Vulnérable vs Sécurisé
Cet extrait compare les tags officiels 7.1.1 et 7.1.2. Le correctif valide la valeur après décodage ; la même version limite aussi les chemins résolus dans locate_template(). Il s’agit du code upstream, pas d’un correctif autonome complet ni d’une démonstration d’exploitation.[2], [3]
Extrait source: wp-includes/template.php — get_page_template()
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
if ( $pagename ) {
$pagename_decoded = urldecode( $pagename );
if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
$templates[] = "page-{$pagename_decoded}.php";
}
}
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Passez à la version corrigée de la branche et vérifiez le code réellement exécuté.[1], [4]
- ✓Inventoriez WordPress exposé sur Internet et repérez les versions non prises en charge antérieures à 4.7.[1], [4]
- ✓En cas d’exposition avant le correctif, examinez les journaux et les fichiers PHP ou comptes inattendus ; un signal ouvre une enquête, sans prouver seul une intrusion.
- ✓Dans vos résolveurs, validez les composants après décodage et limitez le chemin réel canonique aux répertoires autorisés.[1], [3]
- ✓Maintenez Core et les thèmes sur des versions prises en charge ; un changement de thème peut modifier les conditions d’exposition.[1], [4]