Des articles WordPress que vous n'avez jamais écrits
Un article que vous n'avez pas écrit est déjà une preuve d'écriture en base. Souvent il n'apparaît pas dans la liste habituelle : brouillon, privé, auteur fantôme, ou statut que l'interface ne montre pas. On le cherche par date et dans `wp_posts`, pas en scrollant l'écran Articles.
Créés par un admin fantôme ou directement en base, souvent non listés dans l'interface. Cherchez par date, auteur, et dans wp_posts en brouillon ou privé.
Pourquoi ces articles existent
L'attaquant a besoin d'URL indexables sur votre domaine. Un article WordPress est le chemin le plus simple : slug, titre, date, parfois une catégorie déjà populaire. Le contenu est du spam SEO, une redirection, ou une page d'attente qui pointe vers une pharmacie.
Ces contenus sont créés par un compte administrateur que vous ne connaissez pas, par l'API REST si elle est ouverte, ou par une requête SQL directe. Dans ce dernier cas, aucun « nouvel utilisateur » n'apparaît : l'auteur affiché est vous, ou un ID à zéro. C'est pour ça que « je n'ai pas de compte inconnu » ne clôt rien.
Un scan de fichiers ne les voit pas. Ils sont en base. Wordfence peut signaler du « spam dans les posts » s'il est réglé pour ; beaucoup d'installations ne le sont pas. La méthode fiable reste une recherche datée, pas un bandeau vert.
Ils ne sont pas tous dans « Tous les articles »
L'écran Articles de WordPress masque par défaut les brouillons des autres, les privés, les futurs, et parfois les types personnalisés. Un post en `private` ou `draft` n'apparaît pas dans « Publiés ». Un `custom post type` enregistré par un mu-plugin n'apparaît dans aucun menu.
Filtrez « Tous les statuts » si l'interface le propose. Puis passez par Utilisateurs : ouvrez chaque compte et cliquez sur le nombre d'articles. Un auteur « support » avec 80 billets créés un mardi à 4 h du matin n'est pas un stagiaire oublié.
Les pages se traitent pareil. Beaucoup d'attaques créent des `page` et non des `post`, précisément parce que les propriétaires regardent surtout le blog. Ouvrez Pages, même si « on n'en a que cinq ».
- Tous les statuts, pas seulement « Publié ».
- Pages et types personnalisés, pas seulement les articles.
- Compteur d'articles par utilisateur.
- Filtre « modifié » plutôt que « publié ».
Trier par date, auteur, statut
Dans l'admin, triez par date de modification. Les vingt lignes du haut racontent la semaine. Un groupe d'articles créés à la même minute, avec des titres en japonais ou des slugs `loan-best-2024`, n'est pas une coincidance éditoriale.
Si l'auteur affiché est votre compte, ne vous arrêtez pas. Une session volée ou une insertion SQL signe avec votre ID. Comparez le style : un titre que vous n'auriez pas choisi, un contenu sans image à la une, une catégorie que vous n'utilisez plus.
Exportez la liste (titre, slug, date, statut, ID) avant de toucher. Cette liste sert au retrait d'URL et au constat. Effacer d'abord, noter après, c'est perdre le préfixe à désindexer.
Lire `wp_posts` quand l'admin ment
phpMyAdmin ou une console SQL : `SELECT ID, post_title, post_name, post_status, post_date, post_author FROM wp_posts WHERE post_type IN ('post','page') ORDER BY post_modified DESC LIMIT 50`. Remplacez le préfixe `wp_` par le vôtre (il est dans `wp-config.php`).
Vous verrez des lignes que l'interface cache : `auto-draft`, `inherit` (révisions), statuts inventés par un plugin, titres vides avec un slug long. Un `post_status` que WordPress ne connaît pas peut quand même être servi si un fichier pirate intercepte la requête.
Cherchez ensuite dans `post_content` un mot du spam (un domaine, un fragment UTF-8 asiatique, `eval(`, un iframe). Limitez la recherche aux contenus modifiés après une date que vous tenez — par exemple le jour où Search Console a parlé, ou le jour du premier article bizarre.
Pages, révisions, et pièces jointes déguisées
Une révision (`post_type = revision`) peut contenir le payload alors que l'article affiché est propre. Rare, mais réel quand quelqu'un a « nettoyé » l'éditeur sans vider l'historique. Les révisions se lisent dans `wp_posts` ; l'écran Articles ne les liste pas.
Une pièce jointe (`attachment`) avec un `guid` qui pointe vers un `.php` ou un `.html` dans `uploads` n'est pas une image. C'est souvent le kit. Ne vous fiez pas à l'icône dans la médiathèque : ouvrez l'URL.
Les landing pages Elementor ou Divi vivent parfois comme `elementor_library` ou équivalent. Elles n'apparaissent pas dans Articles. Si votre constructeur a une bibliothèque de modèles, ouvrez-la. Un modèle « Japanese SEO » n'est pas un import que vous auriez oublié.
L'admin fantôme qui les signe
Si un auteur inconnu existe, traitez-le comme le signal le plus fiable de l'incident : quelqu'un peut republier sans nouvel exploit. La procédure est dans utilisateurs administrateurs fantômes : noter, supprimer, changer votre propre mot de passe, révoquer les mots de passe d'application.
S'il n'y a pas d'auteur inconnu, l'entrée est ailleurs : XML-RPC, REST, plugin d'import, fichier qui écrit en base. Dans ce cas, supprimer les articles sans fermer l'entrée les ramène. Regardez les journaux d'accès autour de `wp-json/wp/v2/posts` et `xmlrpc.php`.
Un compte « Éditeur » ou « Auteur » suffit à publier. Ne filtrez pas seulement les administrateurs. Tout compte que vous ne pouvez pas nommer sort, quel que soit le rôle.
Supprimer n'est pas désindexer
Une fois les articles frauduleux identifiés, passez-les en 410 (disparu) plutôt qu'en simple brouillon. Un brouillon peut être republier par un cron. Une page qui répond 200 vide reste dans l'index. WordPress, en corbeille, sert souvent une 404 ; videz la corbeille.
Notez les slugs. S'ils partagent un préfixe (`/jp/`, `/loan/`, un dossier aléatoire), un retrait de préfixe dans Search Console est plus efficace que cent retraits unitaires. Voir désindexer des pages piratées.
Ne noindexez pas tout le site « le temps de voir ». Vous perdez les pages légitimes. Les articles sains restent en 200 ; seuls les slugs pirates meurent.
- Liste des slugs avant suppression.
- 410 ou 404, pas 200 vide.
- Corbeille vidée.
- Retrait de préfixe si le motif d'URL est clair.
Empêcher la recréation
Après suppression, surveillez `wp_posts` quarante-huit heures. Une nouvelle ligne à 3 h du matin avec un titre asiatique dit que l'écrivain tourne encore. C'est le même test que pour un footer qui revient : le symptôme n'est pas le fond du dossier.
Coupez XML-RPC si vous ne vous en servez pas, limitez l'API REST aux utilisateurs authentifiés si votre thème le permet, changez les mots de passe panel puis admin, cherchez un must-use plugin. Un plugin « dummy content » ou un import CSV oublié dans `wp-content` peut aussi republier.
Les tâches cron inconnues du compte d'hébergement sont le motif n°1 de « ça revient ». WP-Cron seul ne suffit pas : lisez crontab et le planificateur o2switch / cPanel.
Ce que `site:` doit montrer après
Le lendemain, `site:votre-domaine.fr` peut encore lister les titres pirates : l'index est lent. Ce qui compte, c'est que l'inspection d'URL sur un slug frauduleux renvoie 404 ou 410, et que le HTML d'une page légitime soit le vôtre. Relancez l'indexation des home, contact, et trois pages métier.
Si de nouveaux titres apparaissent dans `site:` après le nettoyage, ne désindexez pas : cherchez le générateur. Désindexer pendant que le script tourne est le geste le plus coûteux de ce type de dossier.
Vous pouvez créer un espace si la base ou les cron vous échappent. En attendant : export de la liste, copie de `wp_posts`, mots de passe panel. Ces trois gestes ne cassent rien.