FlawOpen

flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal

● CVE-2026-87902 · CVSS 9.2[1] · Critique
Recherche · FlawOpen

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]

💡 Explication en Langage Simple (ELI5)

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]
CWE-98
CWE-98 — Contrôle incorrect du nom de fichier pour include/require : l’entrée n’est pas suffisamment limitée avant de choisir un fichier PHP.[1], [7]

Correspondances de référentiels

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éploiementCe que confirment les sources primairesAction à mener
Branche WordPress Core vulnérableLe 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 actifLe 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 lisibleUn 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 conditionnelleL’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

Étape 1

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]

Étape 2

Nouvelle décodification

get_page_template() décode encore le nom ; les versions vulnérables ne validaient pas le candidat décodé.[2], [3]

Étape 3

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]

Étape 4

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()

IMPLÉMENTATION VULNÉRABLE
if ( $pagename ) {
    $pagename_decoded = urldecode( $pagename );

    if ( $pagename_decoded !== $pagename ) {
        $templates[] = "page-{$pagename_decoded}.php";
    }
}
PATCH SÉCURISÉ ET ROBUSTE
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

Sources