WordPress vient de corriger en urgence deux vulnérabilités critiques dans son cœur — dont une RCE pré-authentifiée baptisée wp2shell qui permet l'exécution de code arbitraire sur n'importe quelle installation WordPress 6.9 ou 7.0 sans le moindre compte utilisateur. Si votre site n'est pas encore à jour, considérez qu'il est exposé en ce moment même : des outils de vérification publics circulent déjà, et les premières tentatives d'exploitation en masse ne vont pas tarder à suivre.

Deux CVE, une seule chaîne d'attaque

Le bulletin de sécurité du 17 juillet 2026 corrige deux failles distinctes qui, combinées, forment une chaîne d'exploitation redoutable :

  • CVE-2026-60137 (GHSA-fpp7-x2x2-2mjf) — injection SQL dans le paramètre author__not_in de WP_Query. Découverte par TF1T, dtro et haongo. CVSS WPScan : 5.9 Medium, CVSS CISA-ADP : 9.1 Critical.
  • CVE-2026-63030 (GHSA-ff9f-jf42-662q) — confusion de routes sur l'endpoint REST API /wp-json/batch/v1, qui, chaînée avec CVE-2026-60137, aboutit à une exécution de code distante non authentifiée. Découverte par Adam Kues (Assetnote / Searchlight Cyber). CVSS WPScan : 9.8 Critical.
Versions affectées : WordPress 6.9.0 → 6.9.4 et 7.0.0 → 7.0.1. Les versions 6.8.x et antérieures ne sont pas touchées par la RCE (CVE-2026-63030), mais restent vulnérables à l'injection SQL (CVE-2026-60137). Versions corrigées : 6.8.6, 6.9.5, 7.0.2.

Anatomie technique de wp2shell

Premier maillon : l'injection SQL dans WP_Query

Le paramètre author__not_in de la classe WP_Query accepte un tableau d'ID d'auteurs à exclure des résultats. Le problème : WordPress ne sanitize pas correctement les valeurs transmises à ce paramètre avant leur insertion dans la requête SQL générée. Concrètement, si un plugin, un thème ou une fonctionnalité core transmet des données non filtrées à ce paramètre, un attaquant peut y injecter du SQL arbitraire.

Ce type de faille dans WP_Query n'est pas sans précédent — on a déjà vu des injections similaires via orderby, meta_query ou tax_query. Ce qui change ici, c'est le vecteur d'exploitation : il est exposé directement via l'API REST.

Second maillon : la confusion de routes sur /wp-json/batch/v1

WordPress 6.9 a introduit un endpoint de traitement par lot dans l'API REST : /wp-json/batch/v1. Cet endpoint permet d'envoyer plusieurs requêtes REST en une seule requête HTTP, dans le but de réduire le nombre de round-trips réseau.

La faille réside dans la façon dont cet endpoint résout les routes internes des sous-requêtes. En exploitant une confusion entre les noms de routes et leur résolution interne, Adam Kues a découvert qu'il était possible de forcer l'endpoint batch à exécuter une sous-requête qui appelle WP_Query avec des paramètres contrôlables par l'attaquant — y compris author__not_in.

La chaîne complète ressemble à ceci :

POST /wp-json/batch/v1 HTTP/1.1
Host: target-wordpress.com
Content-Type: application/json

{
  "requests": [
    {
      "method": "GET",
      "path": "/wp/v2/posts?author__not_in[]=1 UNION SELECT ... INTO OUTFILE '/var/www/html/shell.php'-- -"
    }
  ]
}

Sans authentification. Sans plugin tiers. Juste WordPress et son API REST.

Point clé : la combinaison des deux CVE transforme une injection SQL (exploitable conditionnellement) en RCE systématique. CVE-2026-60137 seule ne suffit pas à écrire un webshell — c'est CVE-2026-63030 qui fournit le vecteur sans authentification permettant d'atteindre le paramètre vulnérable.

Pourquoi l'API batch est particulièrement dangereuse ici

L'endpoint /wp-json/batch/v1 n'est pas filtré par les mécanismes habituels de contrôle d'accès des routes REST individuelles. Chaque route REST WordPress peut déclarer ses propres permission_callback — mais le traitement batch a ses propres règles de résolution qui peuvent contourner ces callbacks dans certaines configurations. C'est exactement ce type de surface d'attaque que cherchent les spécialistes de la sécurité des API : un endpoint "méta" qui agrège les appels et dont le comportement de sécurité diffère des routes sous-jacentes.

Il faut également souligner que cet endpoint est accessible via deux chemins distincts :

  • /wp-json/batch/v1 — la route permalink-based classique
  • /?rest_route=/batch/v1 — la route query-string, souvent oubliée dans les règles de filtrage

Ce détail a son importance pour la mitigation, comme on le verra plus bas.

Versions affectées et corrigées

BrancheVersions vulnérablesVersion corrigéeCVE-2026-60137CVE-2026-63030
WordPress 6.8.x6.8.0 → 6.8.56.8.6✅ corrigénon affectée
WordPress 6.9.x6.9.0 → 6.9.46.9.5✅ corrigé✅ corrigé
WordPress 7.0.x7.0.0 → 7.0.17.0.2✅ corrigé✅ corrigé
WordPress ≤ 6.7.xnon affectéenon affectéenon affectée

WordPress a activé les mises à jour automatiques forcées pour ces versions — ce qui est rare et signale la gravité de la situation. Si votre hébergeur les a désactivées (pratique courante en agence), la mise à jour manuelle est impérative.

Mesures de remédiation

1. Mettre à jour immédiatement

C'est la seule vraie correction. Les versions 6.8.6, 6.9.5 et 7.0.2 sont disponibles dans le tableau de bord WordPress (Mises à jour) et via WP-CLI :

wp core update --version=7.0.2 --force

Pour vérifier la version en place :

wp core version

2. Bloquer l'endpoint batch au niveau WAF

Si la mise à jour est impossible immédiatement (maintenance planifiée, tests de non-régression sur un site complexe), le blocage de l'endpoint batch est la mesure d'atténuation la plus efficace. Attention : il faut bloquer les deux formes de l'URL.

Un WAF qui ne bloque que /wp-json/batch/v1 laisse /?rest_route=/batch/v1 entièrement ouvert — c'est la même fonctionnalité, le même code, un chemin différent. Les deux formes doivent être ciblées.

Nginx (règle temporaire)

# À placer dans le bloc server{}, avant le bloc location principal
location ~* ^/wp-json/batch {
    return 403;
}

# Bloquer aussi la forme query-string
if ($arg_rest_route ~* "^/batch") {
    return 403;
}

Apache (.htaccess)

RewriteEngine On
# Bloquer /wp-json/batch/v1
RewriteRule ^wp-json/batch - [F,L]
# Bloquer ?rest_route=/batch/v1
RewriteCond %{QUERY_STRING} rest_route=/batch [NC]
RewriteRule ^ - [F,L]

3. Blocage via Cloudflare

Pour les sites derrière Cloudflare (Free, Pro, Business ou Enterprise), plusieurs niveaux de protection sont possibles :

WAF Custom Rules (Free et +)

Dans le dashboard Cloudflare → Security → WAF → Custom Rules, créer une règle :

(http.request.uri.path contains "/wp-json/batch")
or
(http.request.uri.query contains "rest_route=/batch")

Action : Block. La règle s'applique en temps réel sur l'ensemble du trafic entrant, avant qu'il n'atteigne votre serveur.

WAF Managed Rules — WordPress Ruleset (Pro et +)

Cloudflare déploie généralement des signatures pour les vulnérabilités WordPress critiques dans son WordPress Managed Ruleset. Vérifiez dans Security → WAF → Managed Rules que ce ruleset est activé — une signature wp2shell/CVE-2026-63030 devrait apparaître dans les jours suivant la publication publique du PoC.

Rate Limiting (Free et +)

Ajouter une règle de rate limiting sur /wp-json/ : limiter à 30-60 requêtes POST par minute par IP ralentit significativement toute tentative de scan ou d'exploitation automatisée.

Chemin : /wp-json/*
Méthode : POST
Seuil : 30 requêtes / 60 secondes
Action : Block (10 minutes)

Page Rules / Transform Rules — désactiver l'API REST en production

Si votre site WordPress n'utilise pas l'API REST pour du contenu public (pas de Gutenberg headless, pas d'app mobile), vous pouvez retourner un 403 sur l'ensemble de /wp-json/ via une Transform Rule Cloudflare, en whitélistant uniquement les routes nécessaires.

4. Désactiver l'accès anonyme à l'API REST via WordPress

Indépendamment de la mise à jour, restreindre l'accès anonyme à l'API REST est une bonne pratique défensive qui réduit la surface d'attaque de toute future vulnérabilité dans cette surface :

// Dans functions.php ou un plugin MU
add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! is_user_logged_in() ) {
        return new WP_Error(
            'rest_not_logged_in',
            'L\'API REST est réservée aux utilisateurs authentifiés.',
            array( 'status' => 401 )
        );
    }
    return $result;
} );

Attention : ce filtre bloque également les fonctionnalités légitimes qui utilisent l'API REST anonymement (formulaires de contact, widgets Gutenberg publics, certains plugins de cache). Tester en staging avant de déployer.

5. Vérifier si votre site est exposé

Un outil de test public est disponible sur wp2shell.com pour vérifier si une instance est vulnérable. Son fonctionnement repose sur une vérification passive (pas d'exploitation réelle) : il envoie une requête malformée sur l'endpoint batch et analyse la réponse pour détecter les patterns caractéristiques d'une version vulnérable.

En ligne de commande, une vérification rapide de la version exposée :

curl -s https://monsite.com/wp-json/ | python3 -c "
import json, sys
d = json.load(sys.stdin)
print('WP version:', d.get('namespaces', []))
print('Batch endpoint présent:', 'batch/v1' in str(d))
"

Si batch/v1 apparaît dans la liste des namespaces REST, votre instance expose l'endpoint vulnérable.

Indicateurs de compromission

Si vous avez une fenêtre d'exposition (instance sous WordPress 6.9.x ou 7.0.0/7.0.1 exposée avant le patch), voici ce qu'il faut chercher dans vos logs :

# Requests POST sur l'endpoint batch
grep -E "POST.*/wp-json/batch" /var/log/nginx/access.log

# Forme query-string (souvent oubliée dans les audits)
grep "rest_route.*batch" /var/log/nginx/access.log

# Présence de nouveaux fichiers PHP dans wp-content
find /var/www/html/wp-content -name "*.php" -newer /var/www/html/wp-includes/version.php -ls

# Fichiers PHP dans des répertoires d'upload (signe classique de webshell)
find /var/www/html/wp-content/uploads -name "*.php" -ls

Un accès HTTP 200 sur POST /wp-json/batch/v1 avec un body JSON contenant des valeurs inhabituelles dans author__not_in est un signal d'alarme fort. Une exploitation réussie laisse généralement un fichier .php dans wp-content/uploads/ ou à la racine.

Timeline de divulgation

La chronologie de cette divulgation est intéressante à plusieurs titres. CVE-2026-60137 et CVE-2026-63030 ont été rapportées via le programme de divulgation responsable de WordPress, avec un processus coordonné entre les chercheurs, l'équipe de sécurité WordPress et les hébergeurs partenaires (WP Engine, Automattic, Pressable). Le correctif a été développé et testé en amont de la publication — ce qui explique que les versions 6.8.6, 6.9.5 et 7.0.2 soient sorties simultanément le 17 juillet 2026, le même jour que la divulgation publique.

Ce type de divulgation coordonnée multi-branches est techniquement complexe : WordPress maintient plusieurs branches LTS en parallèle, et un patch de sécurité doit être backporté proprement sur chacune sans introduire de régression. C'est là que des projets comme WordPress échouent parfois — ici, la coordination semble avoir bien fonctionné.

Adam Kues d'Assetnote, qui a découvert CVE-2026-63030, est connu pour ses travaux sur la sécurité des CMS et des API REST. Il avait déjà publié des recherches sur des vulnérabilités similaires dans d'autres plateformes. La dénomination wp2shell est la sienne — elle décrit la capacité à passer d'une instance WordPress non patchée à un shell interactif en une seule requête HTTP.

Contexte et portée de l'impact

WordPress propulse environ 43 % des sites web mondiaux. Les versions 6.9 et 7.0, introduites fin 2025 et début 2026, ont une adoption significative parmi les sites actifs — d'autant que la mise à jour automatique vers 7.0 a été poussée activement. Ce ne sont pas les petits blogs personnels qui sont la cible prioritaire : ce sont les sites e-commerce WooCommerce, les plateformes médias, et les sites institutionnels qui tournent sur WordPress managé chez des hébergeurs mutualisés où les mises à jour peuvent prendre du retard.

La disponibilité d'un outil de test public (wp2shell.com) va accélérer le cycle scan → exploitation. L'expérience des précédentes vulnérabilités critiques WordPress (CVE-2021-44223, CVE-2023-2732) montre que les premières campagnes d'exploitation automatisée commencent 24 à 72 heures après la publication d'un PoC fonctionnel.

Analyse du patch : ce que WordPress a modifié

Sans accès au diff complet (non encore public au moment de la rédaction), les informations disponibles permettent de comprendre les deux corrections appliquées.

Correction de CVE-2026-60137 — Sanitization de author__not_in

La correction consiste à appliquer un cast en entier (absint()) sur chaque valeur du tableau author__not_in avant construction de la clause SQL. C'est le pattern standard pour les paramètres WordPress qui ne doivent recevoir que des entiers positifs (ID d'utilisateurs, de posts, de termes) :

// Avant le patch (simplifié)
$author__not_in = implode(',', $this->query_vars['author__not_in']);

// Après le patch
$author__not_in = implode(',', array_map('absint', $this->query_vars['author__not_in']));

Ce type de correction est chirurgical et ne devrait pas générer de régression, sauf pour du code qui passe délibérément des valeurs non-entières à ce paramètre (ce qui serait de toute façon un bug applicatif).

Correction de CVE-2026-63030 — Validation de routes dans l'endpoint batch

La correction de la confusion de routes dans l'endpoint batch est plus structurelle. Elle introduit une validation stricte des chemins de routes acceptés dans les sous-requêtes batch : seules les routes enregistrées via register_rest_route() sont résolues, et leur résolution passe désormais par les mêmes couches de permission_callback que lors d'un appel direct. La logique de résolution "raccourcie" qui permettait de contourner ces callbacks est supprimée.

Cette correction est applicable seulement sur les branches 6.9 et 7.0, puisque l'endpoint batch n'existait pas dans 6.8.x.

Évaluation du risque selon votre configuration

Tous les sites WordPress 6.9/7.0 ne présentent pas le même niveau de risque effectif. Voici une grille d'évaluation :

FacteurRisque élevéRisque réduit
Exposition de l'API RESTAPI REST publique, pas de restriction IPAPI REST bloquée pour les anonymes
HébergementVPS/dédié sans WAF applicatifHébergeur managé avec WAF activé
CDN/proxyPas de Cloudflare ou WAF en amontCloudflare Pro+ avec WP Managed Rules
Permissions fichiersPHP peut écrire dans le webrootPHP en lecture seule sur le webroot
Droits MySQLUtilisateur MySQL avec FILE privilegeUtilisateur MySQL sans FILE privilege
Version WP6.9.0 → 6.9.4 ou 7.0.0 → 7.0.16.9.5, 7.0.2 ou ≤ 6.8.x

Un point important sur les permissions MySQL : l'écriture d'un webshell via SELECT ... INTO OUTFILE requiert que l'utilisateur MySQL dispose du privilege FILE ET que le chemin cible soit dans le secure_file_priv défini dans my.cnf. Sur les installations WordPress managées (WP Engine, Kinsta, Pantheon), ces conditions sont généralement non réunies — ce qui ne signifie pas que l'injection SQL est sans impact, mais qu'elle ne mène pas directement à un webshell.

Sur les VPS classiques avec MySQL configuré par défaut, les conditions sont souvent réunies.

Ce que cette faille révèle sur les API batch

Au-delà de WordPress, wp2shell pose une question plus large : les endpoints "méta" des API REST — ceux qui agrègent ou proxifient d'autres requêtes — ont des propriétés de sécurité différentes des endpoints qu'ils orchestrent. Un endpoint batch ne bénéficie pas automatiquement des contrôles d'accès des routes individuelles. Si vous développez ou auditez des API, ce type de surface mérite une attention particulière :

  • Les endpoints /batch, /bulk, /multiplex, /fanout sont des cibles de choix pour les chercheurs en sécurité
  • La résolution de routes dans un contexte d'appel imbriqué peut bypasser les permission_callback déclarés sur les routes feuilles
  • Les injections SQL via des paramètres de filtrage (orderby, meta_key, author__not_in) dans les ORM ou les query builders sont sous-estimées par rapport aux injections directes dans des champs de formulaire

Comparaison avec les précédentes vulnérabilités critiques WordPress

wp2shell s'inscrit dans une lignée de vulnérabilités majeures qui ont affecté WordPress core — et non des plugins tiers. Cette distinction est importante : les vulnérabilités dans les plugins touchent un sous-ensemble d'installations, là où une faille dans le core WordPress peut affecter des centaines de millions de sites.

Les précédents les plus comparables :

  • CVE-2023-2732 (mai 2023) — faille dans le theme switcher permettant une SSRF authentifiée. Impact limité par la nécessité d'authentification.
  • CVE-2021-44223 (novembre 2021) — XSS stockée dans l'éditeur de blocs Gutenberg. Moins grave car nécessitait des droits d'éditeur.
  • CVE-2019-8942 / CVE-2019-8943 — la fameuse vulnérabilité de Path Traversal + LFI dans les métadonnées d'images, exploitable par des contributeurs. C'est historiquement l'une des rares RCE pré-auth-like dans le core WordPress moderne.

wp2shell se distingue par son caractère entièrement pré-authentifié sur un endpoint introduit relativement récemment. Les équipes de sécurité de WordPress ont globalement fait du bon travail depuis 2016 pour réduire la surface d'attaque du core — ce qui rend cette faille d'autant plus notable.

Testez votre site WordPress

Entrez l'URL de votre site WordPress pour vérifier s'il est exposé à CVE-2026-63030. L'outil effectue uniquement des vérifications passives : lecture de /wp-json/ et sonde OPTIONS sur l'endpoint batch. Aucune donnée n'est exploitée ni exfiltrée. Ne testez que les sites dont vous êtes responsable.

wp2shell-checker — CVE-2026-63030
https://

Ce test est passif — aucune exploitation. Testez uniquement vos propres sites.

FAQ

Quel est l'impact réel si le FILE privilege MySQL n'est pas disponible ?

L'injection SQL via author__not_in reste exploitable même sans FILE privilege. Un attaquant peut extraire des données de la base (hachages de mots de passe WordPress, clés secrètes, jetons d'authentification, emails des utilisateurs) via une injection SQL classique UNION-based ou blind. Dans ce cas, l'impact est une compromission de données et potentiellement une prise de contrôle du site via les credentials extraits — sans exécution de code directe, mais avec des conséquences tout aussi sévères.

Mon site est sur WordPress 6.8 — suis-je exposé à la RCE ?

Non. CVE-2026-63030 (la RCE via l'endpoint batch) n'affecte pas les branches 6.8 et antérieures. Vous êtes en revanche exposé à CVE-2026-60137 (injection SQL dans author__not_in), qui nécessite une mise à jour vers 6.8.6.

L'API REST de WordPress est-elle désactivable en production ?

Oui, mais c'est une décision à évaluer selon l'usage du site. Gutenberg (l'éditeur de blocs par défaut depuis WP 5.0) utilise l'API REST même pour les administrateurs authentifiés. La désactiver globalement casse l'éditeur. La solution pragmatique est de bloquer l'accès anonyme (filtre rest_authentication_errors) tout en conservant l'accès pour les utilisateurs connectés.

Les mises à jour automatiques WordPress gèrent-elles cette faille ?

WordPress a activé les mises à jour automatiques forcées pour 6.8.6, 6.9.5 et 7.0.2. Si votre hébergeur ne les a pas désactivées (certains le font pour éviter les régressions), votre site devrait avoir été mis à jour automatiquement. Vérifiez dans Tableau de bord → Mises à jour ou via wp core version.

Cloudflare protège-t-il automatiquement contre wp2shell ?

Cloudflare déploie des signatures dans son WAF Managed WordPress Ruleset pour les vulnérabilités critiques, mais il y a toujours un délai entre la publication et le déploiement de la signature. La création d'une Custom Rule ciblant /wp-json/batch et rest_route=/batch est instantanée et ne dépend pas du délai de mise à jour des règles managées.

Comment savoir si mon site a été compromis avant le patch ?

Chercher des fichiers .php récents dans wp-content/uploads/, vérifier les logs d'accès pour des POST sur /wp-json/batch/v1, et utiliser un scanner comme WPScan ou Wordfence pour auditer l'intégrité des fichiers core.

Faut-il désactiver les mises à jour automatiques WordPress ?

Non — cette faille illustre exactement pourquoi les mises à jour automatiques sont utiles. WordPress a pu pousser le correctif sur des millions de sites en quelques heures via ce mécanisme. Le désactiver pour éviter des régressions potentielles est compréhensible en production critique, mais impose une discipline de surveillance et de déploiement manuel très stricte. Si vous le faites, un système de surveillance des nouvelles CVE WordPress (via WPScan API, CERT-FR ou les flux RSS du WordPress Security Blog) est indispensable.

L'extension Wordfence ou iThemes Security protège-t-elle de cette faille ?

Ces extensions déploient leurs propres règles WAF qui peuvent détecter ou bloquer des tentatives d'exploitation. Cependant, aucune extension de sécurité ne remplace la mise à jour du core. Elles peuvent ralentir ou bloquer certains vecteurs, mais face à des exploits 0-day ou récemment publiés, la règle de signature peut ne pas encore exister. Le patch reste la seule protection certaine.