wp2shell (CVE-2026-63030) : la faille RCE non authentifiée qui frappe le cœur de WordPress
wp2shell est une RCE pré-authentification dans WordPress Core (CVE-2026-63030 + CVE-2026-60137). Fonctionnement, versions vulnérables, PoC, détection et remédiation.

Introduction
Le 17 juillet 2026, l'écosystème WordPress a basculé. Une vulnérabilité surnommée wp2shell permet à un attaquant anonyme, sans aucune authentification, d'exécuter du code arbitraire sur une installation WordPress par défaut, sans le moindre plugin tiers. Autrement dit, il s'agit d'une RCE pré-authentification dans le cœur de WordPress, la catégorie de faille la plus critique qui soit pour un CMS qui propulse plus de 40 % du web.
Dans les heures qui ont suivi la publication du correctif, un proof-of-concept fonctionnel est apparu sur GitHub. Cet article décortique le fonctionnement de wp2shell, les versions concernées, la manière de détecter l'exposition et les mesures à prendre pour s'en protéger, avant que les scanners de masse ne trouvent votre site avant vous.
Wp2shell en bref
Wp2shell n'est pas une faille unique, mais le chaînage de deux vulnérabilités du cœur de WordPress.
La première, CVE-2026-60137, est une injection SQL présente depuis la version 6.8. La seconde, CVE-2026-63030, est une confusion de route dans l'API REST, introduite en 6.9. Prises séparément, ces deux failles restent difficiles à exploiter. C'est leur combinaison qui les rend dévastatrices.
Le résultat est une exécution de code à distance sans authentification sur les versions 6.9.0 à 6.9.4 et 7.0.0 à 7.0.1, corrigée dans les versions 6.9.5 et 7.0.2. L'injection SQL, prise isolément, remonte quant à elle jusqu'à la 6.8 et se corrige avec la 6.8.6. Aucun pré-requis n'est nécessaire côté attaquant : une seule requête HTTP anonyme suffit. C'est ce qui explique un score CVSS de 9.1 pour l'injection SQL et de 7.5 pour la confusion de route.
Le schéma ci-dessous résume le déroulé complet de l'attaque, de la requête anonyme jusqu'au shell.

Comment fonctionne wp2shell ?
La force, et la dangerosité, de wp2shell tient à ce chaînage : deux bugs modérément graves isolément deviennent catastrophiques une fois combinés. Décomposons.
Brique 1 : l'injection SQL dans WP_Query (CVE-2026-60137)
Le cœur du problème est un grand classique du type juggling en PHP. La classe WP_Query, qui construit la quasi-totalité des requêtes de WordPress, accepte un paramètre author__not_in censé être un tableau d'identifiants. Le code suppose ce type et concatène les valeurs directement dans la requête SQL, en s'appuyant sur le fait qu'un tableau d'entiers est intrinsèquement sûr.
Le problème apparaît si l'on fournit une chaîne de caractères au lieu d'un tableau : la sanitisation prévue pour le tableau est contournée et la valeur brute atterrit directement dans la clause WHERE.
// Attendu : author__not_in = [1, 2, 3] -> "AND wp_posts.post_author NOT IN (1,2,3)"
// Fourni : author__not_in = "1) AND 1=0 UNION ALL SELECT ... -- -"
// la chaîne est concaténée telle quelle dans le SQL
$where .= " AND {$wpdb->posts}.post_author NOT IN ({$author__not_in})";En pratique, la charge ressemble à une union classique, avec per_page=-1 pour désactiver le fractionnement de la requête et garantir que l'injection complète soit exécutée :
author__not_in=1) AND 1=0 UNION ALL SELECT <23 colonnes> -- -
per_page=-1Cette injection existe depuis WordPress 6.8, mais seule, elle reste bornée : les routes qui exposent author__not_in exigent une authentification. Il manquait une clé pour l'atteindre de manière anonyme, et cette clé, c'est la brique 2.
Brique 2 : la confusion de route REST /wp-json/batch/v1 (CVE-2026-63030)
WordPress expose depuis la 5.6 un endpoint batch : /wp-json/batch/v1. Il permet de regrouper plusieurs sous-requêtes REST dans un seul appel HTTP, puis de les exécuter en série. En interne, WordPress suit ces sous-requêtes dans deux tableaux parallèles : l'un pour la validation (contrôle des permissions et allow-list des endpoints), l'autre pour l'exécution.
La faille, introduite en 6.9, est une désynchronisation de ces deux tableaux. Lorsqu'une sous-requête déclenche une erreur, les deux tableaux se décalent d'un cran. Résultat : la sous-requête numéro N s'exécute sous le handler, et surtout sous le contexte de permissions, de la sous-requête numéro N-1.
Le chaînage : de l'injection bornée à la RCE anonyme
Assemblées, les deux briques donnent la primitive complète :
- L'endpoint
/wp-json/batch/v1reçoit une requête batch imbriquée et malformée. - La désynchronisation (CVE-2026-63030) fait sauter le contrôle de permissions : une route publique sert de couverture à une route sensible.
- L'entrée attaquant atteint
author__not_inet déclenche l'injection SQL (CVE-2026-60137), désormais non authentifiée. - L'injection ne se contente pas de lire la base : elle forge des lignes en base pour obtenir des primitives d'écriture.
De l'injection SQL à l'exécution de code
C'est l'étape la plus élégante de la chaîne. L'injection SQL est transformée en RCE via une série d'abus de fonctionnalités légitimes de WordPress :
- Forge de lignes
wp_postsetwp_options: en injectant des lignes contenant du markup comme[embed]<url-du-site>[/embed], WordPress crée de vraies entrées de cache oEmbed et de transients, avec des identifiants prédictibles (post_name = md5(url + attributs)). - Escalade via
customize_changeset: une lignecustomize_changesetforgée avec leuser_idd'un administrateur réel, complétée par une lignepost_type=request, déclenche unparse_requestexécuté dans le contexte admin. - Création d'administrateur et webshell : la même requête batch embarque un
POST /wp/v2/usersqui crée un nouveau compte administrateur, puis un plugin auto-destructeur exécute des commandes système.
Le résultat final est un shell, ce qui donne son nom à wp2shell. Le tout depuis une seule requête HTTP non authentifiée.
Versions de WordPress affectées et correctifs
| Version WordPress | Statut | Correctif |
|---|---|---|
| < 6.8 | Non affecté | Aucun |
| 6.8.0 → 6.8.5 | Injection SQL uniquement (pas de RCE) | 6.8.6 |
| 6.9.0 → 6.9.4 | Chaîne RCE complète | 6.9.5 |
| 7.0.0 → 7.0.1 | Chaîne RCE complète | 7.0.2 |
| 7.1 beta | Affecté | 7.1 beta2 |
L'endpoint batch existe depuis la 5.6, mais c'est bien la confusion de route introduite en 6.9 qui transforme une injection bornée en RCE anonyme. WordPress a poussé les correctifs via son système de mises à jour forcées. Toutes les installations n'ont cependant pas l'auto-update activé, et les sites gérés manuellement ou figés sur une version restent en danger.
Comment savoir si vous êtes vulnérable à wp2shell ?
Trois approches, de la plus simple à la plus rigoureuse.
1. Vérifier votre version
La plus rapide consiste à regarder votre numéro de version. Si votre site tourne sous 6.9.0 à 6.9.4 ou 7.0.0 à 7.0.1, considérez-le comme vulnérable jusqu'à preuve du contraire. Attention toutefois, la version affichée peut être masquée ou trompeuse (thèmes, reverse proxies, WAF).
2. Tester l'exposition de l'endpoint batch
L'endpoint doit être atteignable de deux manières, et les deux doivent être bloquées :
# Route « propre »
curl -s -o /dev/null -w "%{http_code}\n" https://votre-site/wp-json/batch/v1
# Variante query-string (souvent oubliée par les WAF)
curl -s -o /dev/null -w "%{http_code}\n" "https://votre-site/?rest_route=/batch/v1"Un code autre que 404 ou 403 sur l'une de ces routes indique une surface d'attaque exposée.
3. Détection active (injection SQL en aveugle, non destructive)
La détection fiable repose sur une injection SQL temporelle (time-based blind). On mesure le temps de réponse avec et sans une charge SLEEP, encapsulée dans une table dérivée pour passer les optimisations du moteur :
(SELECT 1 FROM (SELECT SLEEP(5))x)Si la requête avec SLEEP(5) répond systématiquement 5 secondes plus lentement que la requête témoin, le sink d'injection est atteignable. Le laboratoire public wp2shell-lab fournit d'ailleurs un environnement Docker (WordPress 6.9.4 et MySQL) ainsi qu'un script de détection non destructif basé sur ce principe.
Comment se protéger dans l'urgence
Par ordre de priorité :
- Mettre à jour immédiatement vers 6.9.5, 7.0.2 ou 6.8.6. C'est la seule remédiation complète.
- Bloquer les deux formes de la route batch au niveau du WAF ou du serveur web, à savoir
/wp-json/batch/v1et?rest_route=/batch/v1. Ne filtrez pas uniquement/wp-json, sans quoi la variante query-string resterait exploitable. - Restreindre l'API REST aux utilisateurs authentifiés via un plugin, ou un must-use plugin qui rejette les requêtes batch anonymes au niveau du hook
rest_pre_dispatch. - Vérifier les indicateurs de compromission : nouveaux comptes administrateurs, plugins inconnus, lignes suspectes dans
wp_postsouwp_options, requêtes vers/batch/v1dans les logs.
Pourquoi les scanners classiques passent à côté
wp2shell illustre parfaitement les angles morts de l'audit traditionnel.
Le pentest annuel photographie votre sécurité à l'instant T. Une faille publiée le 17 juillet n'existe pas dans un rapport daté du mois de mars, et entre deux audits, vous restez aveugle. Les scanners de version, eux, se contentent de lire un numéro de version, trivialement masquable, sans jamais tester le comportement réel de l'endpoint batch. Enfin, le périmètre incomplet est presque toujours en cause : c'est le sous-domaine oublié (un vieux blog WordPress, un environnement de préproduction indexé) qui tombe en premier, encore faut-il savoir qu'il existe.
La détection de wp2shell n'exige pas un exploit destructeur. Elle exige de cartographier tout votre périmètre, d'identifier les instances WordPress, puis de tester activement mais sans risque la route batch et le sink d'injection, en continu et non une fois par an.
Flawfence détecte wp2shell nativement
Chez Flawfence, la classe de vulnérabilités dont relève wp2shell (abus de l'API REST, confusion de route, injection SQL non authentifiée) fait partie du moteur de scan depuis le premier jour. Ce n'est pas un module ajouté dans la panique après la publication, mais le socle même de notre approche.
Concrètement, face à wp2shell, Flawfence :
- Cartographie automatiquement votre périmètre. Chaque sous-domaine et chaque instance WordPress exposée est découverte, y compris le Shadow IT que vous aviez oublié. Voir notre guide sur comment cartographier le système d'information de son entreprise.
- Teste activement l'endpoint
/wp-json/batch/v1(routes propre et query-string) et détecte le sink d'injection SQL via une méthode temporelle non destructive, sans jamais créer de compte admin ni écrire en base. - Valide chaque résultat par IA, pour zéro faux positif et uniquement des failles réellement exploitables, avec le contexte et le scoring CVSS.
- Surveille en continu. Dès qu'une nouvelle version vulnérable est déployée, ou qu'un sous-domaine apparaît, l'alerte tombe, sans attendre le prochain pentest.
Chronologie de la réponse
wp2shell montre à quel point la fenêtre entre la divulgation d'une faille et son exploitation de masse est courte : quelques heures, pas quelques semaines. Voici comment les événements se sont enchaînés, et à quel moment Flawfence est intervenu.

Le jour même de la divulgation, la détection de wp2shell était déjà en place dans notre moteur de scan, et les premières instances vulnérables remontaient une heure plus tard. C'est toute la différence entre un audit qui tourne en continu et un pentest programmé des mois à l'avance.
FAQ : wp2shell
Qu'est-ce que wp2shell ?
wp2shell est le surnom d'une exécution de code à distance non authentifiée dans le cœur de WordPress, résultant du chaînage de deux vulnérabilités : CVE-2026-63030 (confusion de la route REST /wp-json/batch/v1) et CVE-2026-60137 (injection SQL dans le paramètre author__not_in de WP_Query). Un attaquant anonyme peut obtenir un shell sur une installation par défaut.
Quelles versions de WordPress sont vulnérables ?
La chaîne RCE complète affecte WordPress 6.9.0 à 6.9.4 et 7.0.0 à 7.0.1. L'injection SQL seule remonte à la 6.8. Les correctifs sont 6.9.5, 7.0.2 et 6.8.6.
wp2shell est-il activement exploité ?
Un proof-of-concept fonctionnel est public sur GitHub depuis le 18 juillet 2026, et un laboratoire de reproduction est disponible. Compte tenu du nombre de sites WordPress et de l'automatisation des attaques, une exploitation massive est à considérer comme imminente. Patchez sans attendre.
Comment détecter wp2shell sans compromettre mon site ?
Par une détection en aveugle basée sur le temps. On compare le temps de réponse d'une requête normale à celui d'une requête portant une charge SLEEP, à travers la route batch. Cette méthode est non destructive, car elle ne crée ni compte, ni contenu. C'est l'approche utilisée par le scan de Flawfence.
Bloquer /batch/v1 avec un WAF suffit-il ?
Non. C'est une mesure de mitigation temporaire utile, mais contournable, et elle n'adresse pas l'injection SQL sous-jacente. Pensez à bloquer les deux formes de la route (/wp-json/batch/v1 et ?rest_route=/batch/v1). La seule remédiation complète reste la mise à jour.
Flawfence détecte-t-il wp2shell ?
Oui. La détection des abus d'API REST et des injections SQL non authentifiées fait partie du moteur de Flawfence depuis le début. Le scan identifie vos instances WordPress exposées et teste activement, sans risque, leur exposition à wp2shell, en continu.
Conclusion
wp2shell est un cas d'école : deux bugs anodins pris séparément, un chaînage dévastateur, une surface d'attaque massive et un PoC public en quelques heures. Pour les équipes de sécurité, la leçon est claire : la sécurité de WordPress ne se joue pas une fois par an, mais chaque jour, sur chaque actif exposé, connu ou oublié.
La bonne nouvelle, c'est que détecter cette classe de failles ne demande ni exploit destructeur, ni pentest à 50 k€. Il faut un inventaire exhaustif de votre périmètre et une surveillance continue qui teste le comportement réel de vos endpoints. C'est précisément ce que Flawfence fait, pour wp2shell comme pour la prochaine faille qui n'a pas encore de nom.
Vérifiez votre exposition à wp2shell dès maintenant, il ne vous faudra que 5 minutes.
Discutons de votre exposition externe
Demandez une démo personnalisée de Flawfence et découvrez votre niveau d’exposition réel.
