Sécurisation WordPress : durcir un site que tout le
monde attaque
Une install WordPress par défaut livre sa version et le login de son admin à qui demande. On énumère un site de test en réel, on liste 5 CVE de plugins 2025, puis on durcit et on mesure l'écart.
own2pwn11 min de lecture

Combien de WordPress exposez-vous ?
L'EASM cartographie vos sites WordPress publics, lit leur version et signale ceux qui portent une CVE connue, en continu.
Voir mes WordPress exposésJ'ai monté une installation WordPress fraîche, la toute dernière version, sans le moindre plugin ni thème ajouté. Trois minutes après la fin de l'installeur, avec un simple curl et zéro exploit, ce site m'annonçait sa version dans quatre endroits différents et me donnait le login de son unique administrateur. C'est le point de départ de tout attaquant qui vise WordPress : pas une faille spectaculaire, mais une reconnaissance que le CMS offre par défaut. La sécurisation WordPress commence par comprendre ce que votre site raconte de lui-même, puis à le faire taire.
Cet article n'est pas une liste de vingt astuces recopiées. Toutes les commandes qui suivent, je les ai lancées contre ma machine de test, une instance WordPress jetable dans un conteneur Docker sur 127.0.0.1. Je montre la sortie réelle, j'applique un durcissement, puis je relance exactement les mêmes commandes pour mesurer l'écart. Vous verrez ce qui bouge vraiment et ce qui ne fait que déplacer le problème.
À faire uniquement sur votre propre site
xmlrpc.php ne casse rien, mais reste une reconnaissance active qui laisse des traces dans les logs. Ne la menez que sur un site que vous possédez ou pour lequel vous avez un mandat écrit. Toutes les mesures de cet article ont été faites sur une instance de lab que je contrôle, jamais sur un site tiers.Ce qu'un attaquant lit sur votre WordPress en trente secondes
Avant d'attaquer, on cartographie. Un WordPress exposé répond à une poignée de requêtes non authentifiées qui, mises bout à bout, dessinent une empreinte précise : version du coeur, comptes existants, endpoints ouverts. Rien de tout ça n'est une vulnérabilité en soi. C'est du renseignement, et c'est gratuit. La première brique, c'est la version, parce qu'elle conditionne tout le reste : une fois qu'un attaquant sait que vous tournez en 6.8.2, il n'a plus qu'à consulter les avis de sécurité publiés depuis.
Voici la lecture de version sur mon instance de test. La balise generator est la plus connue, mais elle n'est pas seule : le flux RSS embarque la même information dans une balise generator XML, et chaque feuille de style du coeur est servie avec un paramètre ?ver= qui trahit la version exacte.
$ curl -s http://127.0.0.1:8899/ | grep -i 'name="generator"'
<meta name="generator" content="WordPress 7.1" />
$ curl -s 'http://127.0.0.1:8899/?feed=rss2' | grep -io '<generator>[^<]*</generator>'
<generator>https://wordpress.org/?v=7.1</generator>
$ curl -s http://127.0.0.1:8899/wp-login.php | grep -o 'ver=[0-9.]*' | sort -u
ver=1.13.8
ver=7.1Trois requêtes, une réponse cohérente : WordPress 7.1. Le paramètre ver=1.13.8 est encore plus intéressant, car il ne vient pas du coeur : c'est la version d'un composant chargé sur la page de connexion. Ce genre de numéro permet de fingerprinter une bibliothèque précise et de la confronter aux CVE connues, exactement comme le fait un scanner de vulnérabilité par corrélation de bannière. La reconnaissance passive fournit déjà de quoi prioriser une attaque.
Énumération des comptes : le login offert par l'API REST
Le brute force sur WordPress a un préalable : connaître les noms d'utilisateur. Beaucoup pensent qu'un login n'est pas un secret, et c'est vrai, mais le divulguer à qui le demande divise par deux le travail de l'attaquant. Or l'API REST des utilisateurs de WordPress liste par défaut, sans authentification, tous les comptes qui ont publié. Sur mon lab, une requête suffit :
# Sur un site en permaliens jolis :
$ curl -s http://SITE/wp-json/wp/v2/users
# Sur mon lab en permaliens simples, la meme route via query string :
$ curl -s 'http://127.0.0.1:8899/?rest_route=/wp/v2/users' | jq -c '.[] | {id, slug, name}'
{"id":1,"slug":"editeur_demo","name":"editeur_demo"}Le champ slug est le point sensible : il correspond très souvent au login réel du compte, celui qu'on tape dans wp-login.php. Ici, editeur_demo est à la fois le nom affiché et l'identifiant de connexion. La vieille technique /?author=1, qui redirige vers la page d'archive de l'auteur et révèle son slug dans l'URL, fait le même travail sur les installations qui n'ont pas fermé l'API REST. Une fuite de login est le premier maillon d'une chaîne ; les principes de gestion des fuites de secrets s'appliquent aussi aux identifiants exposés par une API trop bavarde.
xmlrpc.php : l'amplificateur de brute force qu'on oublie
xmlrpc.php est un vestige de l'époque où l'on publiait sur WordPress depuis un client de bureau. Il est toujours présent, toujours actif par défaut, et il pose deux problèmes concrets. Le premier, c'est system.multicall : cette méthode empile plusieurs appels dans une seule requête HTTP. Couplée à wp.getUsersBlogs, qui teste un couple login/mot de passe, elle transforme le brute force en une opération de masse. Au lieu d'une requête par tentative, un attaquant en teste des centaines par requête, sous le radar des limiteurs qui comptent les requêtes. Le second problème, c'est pingback.ping, détourné depuis des années pour lancer des attaques par rebond contre des tiers.
Sur mon lab, l'endpoint répond et se laisse énumérer :
$ curl -s -X POST -d '<methodCall><methodName>system.listMethods</methodName></methodCall>' \
http://127.0.0.1:8899/xmlrpc.php | grep -c '<string>'
81
$ curl -s -X POST -d '<methodCall><methodName>system.listMethods</methodName></methodCall>' \
http://127.0.0.1:8899/xmlrpc.php | grep -oE 'system.multicall|wp.getUsersBlogs|pingback.ping'
pingback.ping
system.multicall
wp.getUsersBlogsQuatre-vingt-une méthodes exposées, dont les trois qui comptent pour un attaquant. Le brute force amplifié par xmlrpc.php est un classique des rapports de test d'intrusion sur un WordPress d'entreprise : la page de login peut être protégée par un limiteur, l'attaquant passe par la porte de derrière. Si vous n'utilisez ni Jetpack, ni l'application mobile, ni les pingbacks, ce fichier ne vous sert à rien et vous coûte une surface d'attaque.
Les plugins et thèmes : la vraie surface d'attaque WordPress
Le coeur de WordPress est audité en permanence par une communauté énorme ; ses failles pré-authentifiées sont rares et rapidement corrigées. Le danger est ailleurs, dans les dizaines de milliers d'extensions et de thèmes tiers de qualité inégale que l'on empile sur une install. Chaque composant ajoute du code exécuté avant même que vous soyez connecté, et chacun peut porter sa propre vulnérabilité. Voici cinq failles réelles divulguées en 2025, toutes vérifiables sur la base NVD, qui illustrent les schémas récurrents.
| CVE (2025) | Composant | Nature | CVSS |
|---|---|---|---|
| CVE-2025-22777 | GiveWP (dons) | Injection d'objet PHP (désérialisation) | 9.8 |
| CVE-2025-3102 | SureTriggers / OttoKit | Contournement d'auth, création de compte admin | 8.1 |
| CVE-2025-4322 | Thème Motors | Prise de contrôle de compte (mot de passe) | 9.8 |
| CVE-2025-6463 | Forminator Forms | Suppression arbitraire de fichiers | 8.8 |
| CVE-2025-24000 | Post SMTP | Contournement d'auth (contrôle d'accès) | 8.8 |
Lisez la colonne du milieu : aucune de ces failles n'est exotique. On retrouve les mêmes familles que dans l'OWASP Top 10 : un contrôle d'accès cassé qui laisse créer un administrateur (SureTriggers, Post SMTP), une désérialisation non fiable qui ouvre l'exécution de code (GiveWP), une validation de chemin insuffisante qui permet de supprimer n'importe quel fichier (Forminator). Le thème Motors, noté 9.8, permettait à un anonyme de réécrire le mot de passe d'un compte existant. Un autre thème de 2025, Alone (CVE-2025-5394, CVSS 9.8), autorisait l'upload de fichiers arbitraires jusqu'à la prise de shell, faute d'un simple contrôle de capacité. Le point commun ? Ces failles sont exploitées en masse dans les jours qui suivent la divulgation, sur des sites qui n'avaient pas encore mis à jour l'extension.
La conséquence est directe pour votre stratégie : la gestion des vulnérabilités d'un parc WordPress, c'est d'abord un inventaire des extensions et de leurs versions, confronté en continu aux flux de CVE. Un plugin abandonné par son auteur ne recevra jamais de correctif : il faut le remplacer, pas l'oublier.
Vérifier une CVE, pas la croire sur parole
Durcissement WordPress mesuré : avant et après
Passons à la pratique. J'ai déposé un mu-plugin (un plugin chargé d'office, sans activation dans l'admin) qui fait quatre choses : retirer la version de partout, couper les méthodes d'authentification de xmlrpc.php, fermer l'énumération des utilisateurs par l'API REST, et poser des en-têtes de sécurité. C'est volontairement minimal et sans dépendance, pour que l'effet de chaque ligne soit mesurable.
<?php
// wp-content/mu-plugins/o2p-hardening.php
// 1. Ne plus divulguer la version (balise generator + flux + the_generator)
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
// 2. Couper les methodes d'auth de XML-RPC (bloque le brute force amplifie)
add_filter('xmlrpc_enabled', '__return_false');
// 3. Refuser l'enumeration anonyme des utilisateurs via l'API REST
add_filter('rest_endpoints', function ($endpoints) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
return $endpoints;
});
// 4. En-tetes de securite (dont une Content-Security-Policy)
add_action('send_headers', function () {
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: SAMEORIGIN');
header('Referrer-Policy: strict-origin-when-cross-origin');
header("Content-Security-Policy: default-src 'self'; object-src 'none'; frame-ancestors 'self'");
});J'ai ensuite relancé exactement les mêmes requêtes qu'au début. Le résultat, mesuré et non supposé :
WordPress 7.1 lisible partout. Après : balise generator absente, flux RSS sans version.slug: editeur_demo. Après : HTTP 404 rest_no_route.CSP, X-Frame-Options, nosniff, Referrer-Policy.200 OK, mais wp.getUsersBlogs renvoie une erreur.Les en-têtes apparaissent, l'API REST des utilisateurs répond 404, la version disparaît des trois sources. Voici la vérification côté REST et en-têtes :
# API REST users, apres durcissement :
$ curl -s -o /dev/null -w '%{http_code}\n' 'http://127.0.0.1:8899/?rest_route=/wp/v2/users'
404
# En-tetes de securite, apres durcissement :
$ curl -sD - -o /dev/null http://127.0.0.1:8899/ | grep -iE 'content-security|x-frame|nosniff'
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: default-src 'self'; object-src 'none'; frame-ancestors 'self'Le piège de xmlrpc_enabled
xmlrpc_enabled à false bloque bien les méthodes d'authentification (mon appel à wp.getUsersBlogs renvoie ensuite "XML-RPC services are disabled on this site"), donc le brute force amplifié tombe. Mais l'endpoint /xmlrpc.php répond toujours 200 et system.listMethods énumère encore quatre-vingts méthodes. Pour le supprimer vraiment de la surface, bloquez le fichier au niveau du reverse-proxy ou du serveur web. Un filtre PHP ne peut pas faire disparaître un fichier que le serveur sert.Ce dernier point est la leçon de fond : masquer la version ou fermer une API ne corrige rien, ça retire du bruit et complique le travail de reconnaissance. C'est utile, mais la Content-Security-Policy et le blocage d'xmlrpc.php sont des mesures de défense en profondeur, pas des correctifs. La seule chose qui neutralise une CVE, c'est la mise à jour.
Le reste du durcissement WordPress : ce qui compte vraiment
Le mu-plugin ci-dessus ferme la reconnaissance et le brute force amplifié. Il ne remplace pas les fondamentaux, qui sont moins spectaculaires mais bien plus déterminants pour ne pas se faire compromettre.
- Mettre à jour, coeur et extensions : les mises à jour automatiques du coeur sont actives par défaut, gardez-les. Pour les plugins et thèmes, activez l'auto-update ou tenez un rythme hebdomadaire. Les CVE du tableau plus haut ne touchent que les sites en retard d'un correctif. Une faille comme wp2shell, la RCE pré-authentifiée du coeur de WordPress rappelle que même le coeur exige une réactivité de mise à jour.
- Réduire la surface : chaque plugin désactivé mais présent reste du code sur le disque, parfois joignable directement. Supprimez ce que vous n'utilisez pas, thèmes par défaut compris. Moins de composants, moins de CVE à suivre.
- Authentification robuste : mots de passe longs et uniques, double authentification sur les comptes administrateurs, et un limiteur de tentatives sur
wp-login.php. Le principe du moindre privilège vaut aussi ici : un rédacteur n'a pas besoin d'un rôle administrateur. - Verrouiller les fichiers sensibles : posez
define('DISALLOW_FILE_EDIT', true);danswp-config.phppour couper l'éditeur de thème et de plugin intégré, une porte royale vers l'exécution de code une fois un compte admin compromis. Protégez l'accès direct àwp-config.phpet interdisez l'exécution de PHP danswp-content/uploads: c'est ce répertoire que visent les failles d'upload arbitraire comme celle du thème Alone. - Sauvegardes testées : une sauvegarde qu'on n'a jamais restaurée est une hypothèse, pas un filet. Externalisez-la, hors du serveur web, et vérifiez la restauration.
Un plugin de sécurité (pare-feu applicatif, surveillance d'intégrité, limitation de login) peut orchestrer une partie de tout ça, à condition de ne pas le prendre pour une dispense de mise à jour. La majorité des sites WordPress compromis l'ont été par une extension obsolète, pas par une faille inédite du coeur.
Vérifier en continu, pas une seule fois
Le durcissement d'aujourd'hui ne dit rien de l'état de demain. Une extension mise à jour peut réintroduire une régression, un développeur peut installer un thème nul part documenté, une CVE peut sortir la nuit sur un plugin que vous jugiez sûr. La sécurité d'un WordPress est un état à surveiller, pas une case à cocher. C'est exactement le rôle d'une gestion de la surface d'attaque externe (EASM) : recenser en continu vos sites publics, lire leur version, et signaler ceux qui portent une faille connue.
C'est ce que fait notre plateforme d'External Attack Surface Management : elle découvre les WordPress exposés d'une organisation, les fingerprinte et corrèle leur version aux CVE publiées, y compris via un vérificateur dédié à la faille wp2shell du coeur. Pour un site à logique métier (paiement, espace client, plugins sur mesure), un scan ne suffit plus : c'est le terrain d'un pentest web en boîte noire, où un humain cherche les contournements d'autorisation et les injections que l'automatisme laisse passer.
À retenir
- Un WordPress par défaut divulgue sa version dans la balise generator, le flux RSS et les paramètres
?ver=, et livre le login de ses comptes via/wp-json/wp/v2/users. Mesuré en réel sur une instance de test. xmlrpc.phpamplifie le brute force viasystem.multicall; le filtrexmlrpc_enabledbloque l'auth mais ne ferme pas l'endpoint, à couper au reverse-proxy.- La vraie surface d'attaque, ce sont les plugins et thèmes tiers : cinq CVE réelles de 2025 (GiveWP, SureTriggers, Motors, Forminator, Post SMTP), toutes des schémas OWASP classiques exploités en masse.
- Masquer la version et fermer une API réduit la reconnaissance mais ne corrige rien : seule la mise à jour neutralise une CVE.
- Le durcissement mesurable (en-têtes, CSP, REST fermée) tient en un mu-plugin de quinze lignes ; les fondamentaux (mise à jour, moindre privilège, 2FA, sauvegardes testées) font le reste.
Sécuriser un WordPress, ce n'est pas empiler des plugins de protection, c'est réduire ce que le site raconte de lui-même et corriger vite ce qui a une CVE. Si vous voulez savoir combien de WordPress votre organisation expose et lesquels portent une faille connue, la plateforme EASM d'own2pwn les cartographie en continu ; pour un audit manuel d'un site sensible, parlons de votre périmètre.
Questions fréquentes sur la sécurisation WordPress
Comment savoir si mon site WordPress est vulnérable ?
La reconnaissance est à la portée de tous : la version du coeur fuite dans la balise generator, le flux RSS et les paramètres ?ver= des scripts, et l'API REST /wp-json/wp/v2/users livre le login des comptes. Comparez la version exposée aux avis de sécurité, listez vos extensions et confrontez chacune aux CVE publiées sur le WPScan feed ou la base NVD. Un scanner de vulnérabilité automatise cette lecture sans exploiter la faille.
Faut-il désactiver xmlrpc.php sur WordPress ?
Oui si vous n'utilisez ni l'application mobile, ni Jetpack, ni les pingbacks. Le fichier expose system.multicall, qui permet de tester des centaines d'identifiants dans une seule requête HTTP, et pingback.ping, détourné pour des attaques par rebond. Le filtre xmlrpc_enabled bloque les méthodes d'authentification mais laisse l'endpoint répondre : pour le couper vraiment, bloquez /xmlrpc.php au niveau du reverse-proxy ou du serveur web.
Comment cacher la version de WordPress ?
Retirer la balise generator du en-tete HTML ne suffit pas : la version se lit aussi dans le flux RSS (?feed=rss2), dans readme.html sur les anciennes versions, et dans les paramètres ?ver= des feuilles de style et scripts. Un durcissement sérieux neutralise ces quatre sources d'un coup. Attention : masquer la version n'est pas un correctif, seulement du bruit. La seule vraie protection reste la mise à jour.
Un plugin de sécurité WordPress protège-t-il vraiment ?
Un plugin de sécurité aide sur la surveillance des fichiers, la limitation des tentatives de connexion et le pare-feu applicatif, mais il ne remplace pas les mises à jour. La majorité des compromissions passent par une extension obsolète, pas par le coeur. Un plugin de plus, c'est aussi du code de plus à maintenir : chaque composant tiers ajoute des lignes qui peuvent porter leur propre faille, comme les CVE listées dans cet article.
Comment empêcher le brute force sur WordPress ?
Limitez les tentatives de connexion sur wp-login.php, coupez xmlrpc.php qui permet de multiplier les essais, et imposez des mots de passe longs plus une authentification à deux facteurs sur les comptes administrateurs. Renommer la page de login ralentit un scan automatique sans le stopper. Le vrai levier reste la robustesse des identifiants : un mot de passe unique de vingt caractères rend le brute force économiquement absurde.
Faut-il un pentest pour un site WordPress ?
Pour un blog vitrine, un durcissement rigoureux plus un scan régulier couvrent l'essentiel. Un pentest web se justifie dès qu'il y a de la logique métier : espace client, paiement, formulaires qui écrivent en base, plugins sur mesure. L'audit humain trouve ce qu'un scanner ne voit pas, comme un contournement d'autorisation entre deux comptes ou une injection dans un endpoint custom. Le coeur WordPress est bien testé ; votre code, non.
Veille sécurité
La suite, une fois par mois
Ce qui bouge vraiment sur la surface d'attaque externe, NIS2 et la sécurité applicative, écrit par le pentester qui signe ces articles. Un envoi par mois, désinscription en un clic.
Votre adresse ne sert qu'à cet envoi. Voir la politique de confidentialité.
Articles liés
appsec
Audit de sécurité informatique : grille, exemple de rapport et prix
Audit de sécurité informatique : ce que chaque type d'audit prouve vraiment, une grille de contrôles concrète, un extrait de rapport anonymisé et les prix affichés. Le volet technique, sans jargon.
appsec
Pentest en entreprise : pourquoi, quand et quel type commander
Pourquoi une entreprise commande un pentest : risque, conformité NIS2 et DORA, exigences clients. Quand le faire, quel type choisir (black, grey, white box, API, red team) et comment cadrer un prestataire.
appsec
OWASP ASVS et WSTG : la méthode réelle d'un pentest web
L'OWASP ne se résume pas au Top 10. L'ASVS 5.0 dit ce qu'une appli doit prouver, le WSTG comment le tester. Mapping d'une méthodo de pentest et dix contrôles ASVS niveau 2 vérifiés en mission.