
Détecteur non destructif pour CVE-2026-64638 (XSS2Shell) — primitive de réflexion XSS pré-authentification WordPress
Détecteur non destructif et sans dépendances de la primitive de réflexion CVE-2026-64638 (« XSS2Shell ») dans wp-login.php de WordPress.
CVE-2026-64638 est une XSS réfléchie pré-authentification dans le cœur de WordPress, divulguée par PWN.AI le 2026-08-07 (CVSS 8.9, CWE-79) et corrigée dans la version 7.0.3 avec des rétroportages vers toutes les branches maintenues (6.9.6, 6.8.7, 6.7.6, 6.6.6, 6.5.9, …).
La cause racine est une différence d’analyse syntaxique entre strip_tags() de PHP et l’assainisseur KSES de WordPress :
strip_tags() refuse de reconnaître une balise lorsque des espaces suivent <, donc un nom d’utilisateur comme < area id=x> survit en tant que texte brut.<area id="x"> dans le message d’erreur de connexion.Cela produit une injection DOM choisie par l’attaquant avec des attributs id/class/href choisis — la primitive derrière la chaîne multi-étapes publiée (dom clobbering → REST JSONP → vol de mot de passe d’application → téléversement d’extension → RCE contre une victime administrateur connectée).
Deux sondes non destructives (un échec de connexion avec un nom d’utilisateur marqueur aléatoire) :
<b>marker</b> apparaît non échappé dans la réponse d’erreur.< area id=marker> survit à strip_tags() et réapparaît comme élément vivant/normalisé (p. ex. area id="marker") dans la réponse.Aucun payload n’exécute quoi que ce soit ; l’outil mesure uniquement si le HTML de l’attaquant est rendu comme DOM vivant. Extras facultatifs :
--version — identifier la version du cœur via la balise <generator> du flux.--jsonp — vérifier que l’enveloppe REST JSONP (_jsonp/_envelope) utilisée par la chaîne publiée est accessible.python3 xss2shell_check.py https://example.com
python3 xss2shell_check.py --jsonp --verbose https://example.com
python3 xss2shell_check.py --version https://example.com
python3 xss2shell_check.py --json https://example.com
Python 3.6+, bibliothèque standard uniquement. Aucune dépendance.
| Code | Signification |
|---|---|
| 0 | VULNÉRABLE (primitive de réflexion présente) |
| 1 | CORRIGÉ / NON VULNÉRABLE |
| 2 | ERREUR (inaccessible, défi WAF, réponse inattendue) |
<area id="…">).
Le style de guillemets varie selon la génération de KSES (ancien analyseur
personnalisé : <area id=x> ; DOMDocument : <area id="x"> /
<area id="x" />), donc toutes les formes sont recherchées. Un passage
brut de < area …> sans réanalyse est un texte inerte dans le
navigateur, pas la primitive — il est signalé comme RAW_TEXT_ONLY et
ne déclenche pas de faux positif.login_errors personnalisé ou
un CDN/WAF réécrit les réponses, ou si le message d’erreur de connexion
ne réfléchit jamais le nom d’utilisateur.Tests de sécurité autorisés uniquement. Cet outil est destiné exclusivement aux tests de systèmes que vous possédez ou pour lesquels vous disposez d’une autorisation écrite explicite. Les tests non autorisés sont illégaux dans la plupart des juridictions.
| Option | Rôle |
|---|
--version | identifier la version du cœur (balise generator du flux, méta page d’accueil en secours) |
--jsonp | vérifier également que l’enveloppe REST JSONP (_jsonp/_envelope) est accessible |
-v, --verbose | afficher des extraits de réponse des sondes (preuves pour les rapports) |
--json | résultat JSON lisible par machine (CI / automatisation) |
| Comportement observé | Verdict | Sortie |
|---|
<b>marker</b> renvoyé non échappé | RAW_HTML — vulnérable | 0 |
< area id=marker> réanalysé en un <area id="marker"> vivant (toute forme de guillemets / forme vide) | AREA_BYPASS — vulnérable | 0 |
| Nom d’utilisateur échappé en HTML | ESCAPED — non vulnérable | 1 |
| Balises supprimées, le texte reste | STRIPPED — non vulnérable | 1 |
< area …> brut traverse mais n’est jamais réanalysé | RAW_TEXT_ONLY — texte inerte, non vulnérable | 1 |
| Aucune réflexion du tout | NOT_REFLECTED — non vulnérable | 1 |
| Sonde bloquée (HTTP ≥ 400 / page de défi) ou cible inaccessible | ERROR | 2 |