WordPress · 9 min · publié le 26 février 2025 · mis à jour le 25 septembre 2025

API REST WordPress abusée : utilisateurs créés, contenu injecté

L'API REST WordPress (`/wp-json/`) n'est pas une faille par défaut. Elle le devient quand l'enregistrement est ouvert, qu'un plugin expose `users` trop largement, ou qu'une clé d'application survit au mot de passe. Voici comment le voir, fermer l'entrée, et lister ce qui a déjà été créé.

Réponse directe

L'endpoint users peut être ouvert trop largement. Fermez l'enregistrement, listez les comptes récents, restreignez l'API après nettoyage si vous n'en avez pas besoin.

rest api wordpress piratage wp-json users api wordpress spam

Ce que l'endpoint users raconte déjà

Sur beaucoup de sites, `https://votre-domaine.fr/wp-json/wp/v2/users` répond encore avec une liste d'identifiants, de slugs et parfois d'avatars. Ce n'est pas « le piratage » : c'est une surface. Un bot s'en sert pour tester des mots de passe, pour créer un compte si l'enregistrement est ouvert, ou pour viser un login connu. Fermer cet énumération après coup ne retire pas les comptes déjà posés.

Le signal utile n'est pas « l'API existe » — elle existe sur tout WordPress récent. C'est : des utilisateurs dont vous n'avez pas la création, des articles publiés sans passage par l'admin, des commentaires ou des médias poussés par `POST` alors que personne n'était devant l'écran. Croisez la date de ces objets avec les journaux d'accès sur `/wp-json/`.

Si l'admin est inaccessible ou lente, WP-CLI (`wp user list`, `wp post list --post_status=publish`) donne le même inventaire sans ouvrir le navigateur. Ce n'est pas un nettoyage, c'est le constat. Voir WP-CLI pour constater.

Un plugin « désactiver l'API REST » posé pendant l'attaque casse WooCommerce, Jetpack ou l'app du prestataire, et ne retire aucun compte déjà créé.

Enregistrement ouvert et rôles par défaut

Réglages → Général → « Tout le monde peut s'enregistrer » est le cas le plus bête et le plus fréquent. Le rôle par défaut « Abonné » n'est pas anodin si un plugin élève ensuite les privilèges, ou si l'API d'un constructeur permet à un abonné d'écrire. Fermez l'enregistrement sauf besoin métier réel (espace membre, WooCommerce a son propre flux).

WooCommerce crée des clients à la commande : ce n'est pas « l'enregistrement ouvert ». Distinguez les deux. Un pic de clients avec des emails jetables oriente plutôt vers un test de checkout ou un abus de formulaire ; un pic d'administrateurs ou d'éditeurs oriente vers l'API ou une faille de plugin.

Un abonné devenu administrateur est un autre dossier : faille, REST mal restreinte, ou accès base. Traitez-le comme une élévation de privilège, pas comme un simple spam de comptes.

  • Enregistrement global : fermé, sauf justification écrite.
  • Rôle par défaut : abonné, jamais éditeur.
  • Liste des users créés sur 30 jours, triée par rôle.

Contenu injecté via l'API, pas via wp-admin

Des pages de pharmacies, des articles vides avec un lien, un média PHP déguisé : l'interface d'admin peut rester « normale » si l'attaquant n'y est jamais passé. Les révisions, l'auteur technique et les user-agents `WordPress/` ou outils d'API dans les access.log le montrent. Chercher uniquement dans Apparence → Éditeur rate ce canal.

Les plugins de constructeur (Elementor, WPBakery) et les types de contenu custom exposent leurs propres routes. Une route mal capée crée un article sans que « Articles » dans le menu ne soit le chemin d'entrée. Comparez `guid` et `post_author` des contenus récents : un auteur « admin » que vous n'avez pas utilisé à cette heure est un indice.

Si le contenu injecté est du spam SEO déjà indexé, coupez la génération puis désindexez. L'API n'est que le tuyau. Le plan de site et les permaliens font le reste. Voir le guide pages spam.

Restreindre sans casser WooCommerce ou l'app mobile

Couper `/wp-json/` au pare-feu « pour être sûr » casse le checkout WooCommerce (Store API), les blocs Gutenberg, l'app officielle, Jetpack, et une bonne partie des constructeurs. Restreignez plutôt : énumération des users, création de users pour les non authentifiés, méthodes que vous n'utilisez pas. Un WAF qui bloque `users` en GET public et laisse le Store API est plus utile qu'un couteau.

Si vous n'avez aucune app, aucun headless, aucun Zapier : vous pouvez durcir fortement. Si vous avez une PWA ou un prestataire qui pousse le catalogue, dressez la liste des routes nécessaires avant de filtrer. Casser le tunnel de paiement pour « fermer l'API » est un mauvais échange — surtout si un skimmer checkout est déjà le vrai risque.

Après restriction, testez comme un client : ajout panier, paiement, compte. Puis comme un anonyme : `users` ne doit plus lister vos logins. Les deux tests, pas un seul.

Clés REST, application passwords et webhooks

WooCommerce → Réglages → Avancé → REST API : des clés `ck_` / `cs_` avec lecture ou écriture. Une clé « Zapier 2021 » ou « old ERP » avec `write` vaut un administrateur. Révoquez ce que vous ne pouvez pas nommer, tournez le reste. Les webhooks WooCommerce (commande créée, etc.) partent vers une URL : si elle a changé, les événements vont ailleurs. Même silence que pour Stripe ou PayPal.

Les application passwords WordPress (utilisateurs → profil) survivent au changement du mot de passe principal. Listez, révoquez l'inconnu. Une app « IFTTT » de 2022 est une session permanente.

Un `.env` ou un wp-config qui contient encore l'ancienne clé, un staging qui la réutilise, un prestataire qui l'a dans un tableur : tourner dans l'admin ne suffit pas si la copie vit ailleurs. Traitez les secrets comme le SMTP — chez l'émetteur, puis dans chaque consommateur.

  • Clés WooCommerce : aucune sans nom et sans besoin.
  • Webhooks : URL encore la vôtre.
  • Application passwords : liste vide ou nommée.
Révoquer une clé n'efface pas ce qui a déjà été lu (commandes, clients). Le constat fuite décide de la suite.

Lister les comptes et révisions récents

Triez les utilisateurs par date d'enregistrement. Tout compte admin / éditeur que personne n'endosse : exportez (id, email, rôle, date), puis retirez le rôle ou supprimez après copie. Forcez la déconnexion de tous (`wp user session destroy --all` ou régénération des clés AUTH dans `wp-config`). Inverser — changer votre mot de passe en laissant le fantôme — laisse une session ouverte.

Dans les articles et pages, filtrez par date. Une page créée à 4 h avec un contenu hors sujet n'est pas « un stagiaire ». Regardez aussi les révisions : un article légitime dont le HTML a été enrichi d'un script via l'API est plus discret qu'une page neuve.

Les médias : un `*.php.jpg` ou un fichier dans `uploads` poussé par l'API est une porte, pas un simple spam. Interdire l'exécution PHP dans uploads fait partie du refermeture, pas du diagnostic.

Ce qu'un pare-feu d'API ne remplace pas

Wordfence, un WAF Cloudflare, un plugin « disable REST » : ils réduisent la surface pour la suite. Ils ne retirent pas un utilisateur déjà admin, ni un article déjà publié, ni une clé déjà émise. Les poser pendant l'attaque ajoute des faux positifs (le checkout qui casse) et du bruit dans les logs.

La faille d'origine est souvent un plugin (JWT, membership, formulaire) qui enregistre une route trop ouverte. Désactiver l'API globale et garder le plugin vulnérable, c'est fermer la fenêtre et laisser la porte. Comparez le plugin à sa version officielle, ou retirez-le.

xmlrpc.php est un canal distinct. S'il est encore ouvert avec `system.multicall`, traitez-le à part. Ce n'est pas l'API REST, mais le résultat se ressemble : brute force, pingbacks, parfois création de contenu.

Après nettoyage : qui a encore le droit d'écrire

Dressez la liste courte : qui a besoin de `edit_posts`, qui a besoin d'une clé, quelle app appelle encore `/wp-json/`. Tout le reste : lecture seule ou rien. Relisez cette liste une semaine plus tard — les comptes « temporaires » du prestataire ont la vie dure.

Si le site est headless ou branché à une app, documentez les routes. Le prochain incident ira plus vite. En attendant, les quatre gestes qui ne cassent rien restent : copie, panel, ticket hébergeur, test visiteur. Vous pouvez déclarer le dossier sans envoyer d'accès tout de suite.

Critère simple : si vous ne savez pas pourquoi une route `POST` est publique, elle ne doit plus l'être.

Questions fréquentes

Faut-il désactiver complètement l'API REST ?

+
Seulement si rien ne s'en sert (pas de WooCommerce, pas d'app, pas de blocs dynamiques). Sinon, restreignez users et les méthodes d'écriture anonymes. Une coupure brute casse le tunnel de paiement plus souvent qu'elle ne « sécurise ».

Comment savoir si des utilisateurs ont été créés par l'API ?

+
Date d'enregistrement, rôle, et access.log sur `/wp-json/wp/v2/users`. L'admin WordPress ne distingue pas toujours l'origine. Un user créé pile après un pic de POST sur cette route n'est pas un hasard.

Un compte « Abonné » peut-il publier via l'API ?

+
Pas avec le cœur seul. Un plugin mal capé, une capability ajoutée, ou une élévation ultérieure, oui. Ne vous arrêtez pas au libellé du rôle : lisez les capabilities et les routes du plugin.

Les clés WooCommerce suffisent-elles à injecter du contenu ?

+
Une clé avec permission lecture ne publie pas d'articles. Une clé écriture sur produits / commandes / coupons suffit à pourrir le catalogue. Révoquez l'inconnu, même « read ». Les données ont pu partir.

Dois-je prévenir la CNIL ?

+
Pas automatiquement. Des comptes spam sans lecture de table clients, ce n'est en général pas une violation. Si l'API a permis d'exporter des commandes ou des users, le constat décide. La notification, si elle est due, vous incombe.
À lire ensuite
Rôle utilisateur élevé WP-CLI pour constater Clés REST WooCommerce WordPress piraté Fuite de données clients Déclarer mon site