Nettoyer site WordPress infecté : corriger wp_options et wp_postmeta compromis

Un site WordPress “infecté” n’a pas toujours l’aspect d’un virus visible. Souvent, le premier signal ressemble à autre chose: une redirection aléatoire, des mots-clés qui apparaissent dans le HTML sans que personne ne les ait saisis, des pages qui s’ouvrent avec un contenu différent selon l’heure ou le navigateur, ou une montée soudaine du trafic sur des URLs qui n’ont rien à voir avec votre activité.

Quand l’hypothèse “compromission” se confirme, on finit presque toujours par regarder du côté de la base. Et, dans les cas que je rencontre le plus souvent, les tables wp options et wppostmeta sont le lieu où l’attaque laisse des traces durables. Pas forcément parce que tout est “stocké” là, mais parce que WordPress utilise ces données pour piloter des comportements, injecter des morceaux de contenu, activer des plugins ou des scripts, et faire remonter des métadonnées exploitables.

L’objectif ici est concret: vous aider à nettoyer site WordPress infecté en examinant précisément wp options et wppostmeta, puis en corrigeant ce qui doit l’être, sans casser le site au passage.

Comprendre ce que vous corrigez vraiment

Avant de toucher à la base, il faut accepter une réalité: WordPress n’est pas un simple CMS, c’est aussi un moteur de configuration. wp options regroupe des options globales et de nombreux paramètres qui influencent le fonctionnement du site. wppostmeta contient des métadonnées associées aux publications, pages, produits, ou tout autre type de contenu.

Dans une compromission, les attaquants cherchent généralement deux choses:

Persistances: quelque chose qui survivra aux suppressions de fichiers (donc, les entrées base sont pratiques). Exécution de logique: par exemple, du PHP injecté, ou des données qui déclenchent du chargement de scripts, ou encore des “champs” que votre thème ou vos plugins utilisent.

Attention à une confusion fréquente: on croit souvent que “mettre à zéro wp_options” règle tout. En réalité, cette approche fait presque toujours plus de mal que de bien, car vous pouvez détruire des réglages légitimes et casser des plugins. Votre job consiste plutôt à identifier ce qui est anormal, puis à supprimer ou corriger les entrées suspectes.

Signes qui orientent vers wp options et wppostmeta

Les indices qui pointent vers ces deux tables ne sont pas théoriques. Ils se voient sur un site déjà “souillé”, souvent via les symptômes suivants:

    Des balises ou scripts apparaissent dans le rendu, même après désactivation temporaire de certains plugins. Des redirections ou injections semblent liées à certaines pages ou à un comportement variable. Des réglages “bizarres” apparaissent dans l’admin (parfois sans que vous les ayez faits), puis disparaissent après purge, avant de revenir. Le site est plus “lourd” que d’habitude, avec des requêtes externes inattendues.

Dans ces contextes, wp options peut contenir des clés d’activation ou des données d’injection utilisées au runtime. wppostmeta, elle, est souvent exploitée pour stocker des champs détournés que le thème ou des plugins “récupèrent” dans le front.

Un détail que je garde en tête quand je fais une analyse: si la compromission est récente, les entrées suspectes ont souvent été créées après coup. Leur date, leur format, et leur cohérence avec le reste du site deviennent des signaux. WordPress ne garantit pas que chaque champ a une “date visible” dans la base, mais on peut raisonner par observation de structure et par comparaison avec les contenus habituels.

Première étape indispensable: sauvegarde et environnement de test

Avant de lancer une requête SQL “pour nettoyer”, sécurisez le terrain.

    Faites une sauvegarde complète de la base. Si possible, clonez la base vers un environnement de test. Le but n’est pas seulement de “pouvoir revenir”, c’est de pouvoir tester l’impact de suppressions sur 1 à 2 pages, sans redescendre le site en production.

Sur un projet réel, j’ai déjà vu une suppression “rapide” dans wp_options qui semblait anodine, puis qui a réactivé un comportement plus discret: le site continuait d’afficher le contenu normal, mais les pages d’administration devenaient instables. Le problème venait d’une option qui servait à gérer le cache d’un plugin, pas de l’infection elle-même. Le site n’était pas “cassé”, mais l’équipe a perdu une journée à reconstituer la cause.

Si vous ne pouvez pas cloner, utilisez au minimum une restauration test sur une copie de sauvegarde.

Méthode de repérage: chercher l’anormal, pas le “suspect par intuition”

Le piège classique consiste à supprimer toutes les options qui “contiennent des scripts” ou “ressemblent à du code”. Si on fait ça sans méthode, on détruit des champs qui sont peut-être légitimes (par exemple, un shortcode générant du HTML stocké dans une option, ou un plugin de suivi qui stocke un identifiant, etc.).

L’approche robuste consiste à:

    regarder les clés (option name) dans wpoptions et les meta key dans wppostmeta, repérer les valeurs incohérentes avec les usages du site, identifier les entrées “qui n’ont pas d’équivalent” dans votre historique, vérifier si le thème ou des plugins utilisent ces valeurs.

Ce que je regarde dans wp_options

Dans wp_options, je cherche en priorité:

    des clés inconnues ou très “génériques” pour un site spécifique (par exemple, une clé qui ne correspond à rien de votre stack habituelle), des clés qui semblent liées à l’exécution de contenu côté front (options qui pilotent des injections, des encarts, des réglages de miniatures, des scripts), des valeurs qui contiennent des signatures typiques: URL externes, chaînes qui ressemblent à du code PHP (souvent on voit des motifs comme eval(, base64_decode(, ou des extraits de fonctions), ou du HTML injecté de manière répétitive.

Je dis bien “motifs”, pas “preuve parfaite”. Une base peut contenir des chaînes techniques sans que ce soit une injection active. Par exemple, un plugin de backup peut stocker une commande ou un log encodé. C’est pour cela qu’on croise avec le contexte.

Ce que je regarde dans wp_postmeta

Dans wp postmeta, je cherche les metakey qui:

    ne correspondent pas à votre écosystème habituel (ce que vous connaissez des plugins installés, des champs ACF, des champs SEO, etc.), portent des valeurs qui ne collent pas au type de champ attendu, déclenchent une lecture dans le thème: certains thèmes ou plugins “récupèrent” des meta et les affichent ou les traitent (même si c’est censé être protégé, la logique peut être contournée).

Une métadonnée corrompue peut aussi être un “conteneur” pour stocker un payload. Dans ce cas, la valeur ressemble moins à un champ utile et plus à du bloc injecté.

Exemples concrets d’anomalies à surveiller

Chaque site a ses particularités, mais certains schémas reviennent.

1) Des URLs externes répétées dans les valeurs

Quand je vois des valeurs contenant des domaines qu’on ne reconnaît pas, et qui reviennent partout, je traite ça comme un signal. Si une injection est active, ces URL apparaissent souvent en cascade: une option globale, puis une meta par page ciblée.

Ce qui aide: comparez les pages qui “dysfonctionnent” (celles qui redirigent, celles qui affichent un contenu étrange) et regardez si les métadonnées associées contiennent ces valeurs. Si seulement 3 pages ont ces meta, alors vous pouvez cibler précisément, au lieu de casser toute la base.

2) Du HTML ou des scripts “hors contexte” dans wp_postmeta

Un champ de type “description produit” peut contenir du HTML, c’est normal parfois. En revanche, si une meta_key censée être un slug ou un identifiant contient un bloc complet de script, là, le doute devient sérieux.

Je me méfie aussi des encodages: des chaînes base64, des fragments qui ressemblent à une structure d’obfuscation. Sans affirmer à 100 pour cent à ce stade, je considère ça comme un candidat à l’investigation.

3) Des options qui pilotent des comportements

Certaines options sont très “WordPress”. Par exemple, des options de cache, de cron, ou de configuration. Mais dans un site compromis, on peut trouver des options non standards. Là encore, on ne supprime pas au hasard. On vérifie l’usage dans le code: votre thème, vos plugins, et les fichiers PHP modifiés.

Même si vous n’avez pas envie de parcourir toute la base du code, vous pouvez au moins:

    lister les différences entre fichiers (via timestamps et checksum si vous avez accès aux dépôts), désactiver temporairement les plugins non essentiels, tester si l’injection persiste.

Le but est de savoir si vous faites face à une persistance en base, ou à une exécution depuis des fichiers.

Inspection pratique de wp options et wppostmeta (sans casser)

Je vous propose une démarche qui limite les dégâts.

Identifiez d’abord les entrées candidates. Vérifiez ensuite si elles sont réellement utilisées. Corrigez en supprimant ou en remplaçant uniquement ce qui est anormal, puis testez.

Comme la syntaxe exacte dépend de votre préfixe (et WordPress peut utiliser wp_ ou un autre préfixe), adaptez wp_ à votre cas.

Requêtes de tri utiles

Sur un clone de base (ou en production si vous êtes sûr et accompagné), vous pouvez filtrer grossièrement par patterns.

Par exemple, pour repérer des options dont la valeur ressemble à du code ou contient des URL:

SELECT option_name, LENGTH(option_value) AS len FROM wp_options WHERE option_value LIKE '%http%' OR option_value LIKE '%eval(%' OR option_value LIKE '%base64%' ORDER BY len DESC LIMIT 50;

Je mets volontairement des LIKE approximatifs. Ce sont des “radars”, pas des verdicts.

Pour wp postmeta, même logique sur la valeur, puis focus sur les metakey:

SELECT post_id, meta_key, LENGTH(meta_value) AS len FROM wp_postmeta WHERE meta_value LIKE '%http%' OR meta_value LIKE '%eval(%' OR meta_value LIKE '%base64%' ORDER BY len DESC LIMIT 100;

Ensuite, vous regardez les post_id concernés. Si vous voyez que la majorité des valeurs suspectes pointent vers quelques pages précises, c’est souvent plus simple à corriger que si tout le site est touché.

Ciblage par cohérence

Un autre signal, c’est la cohérence des longueurs et des formats. Sur un site sain, les longueurs des meta key connues ont tendance à rester dans des plages raisonnables. Si une metakey “standard” devient soudainement énorme, ou si elle change complètement de contenu, vous tenez un axe.

C’est là que la connaissance de vos plugins fait gagner du temps. Par exemple, un plugin SEO peut stocker des titres, des descriptions, des images. Ces contenus ne contiennent généralement pas des blocs scripts complets.

Corriger les entrées: supprimer, remplacer, ou ignorer?

Il existe trois scénarios.

Scénario A: entrée clairement malveillante

Si vous trouvez une option ou une meta qui contient un payload évident (contenu obfusqué, fragments PHP, script injecté avec chargement externe), la correction la plus sûre est souvent de supprimer ces entrées.

Mais faites-le en ciblant. Supprimer toute une table, ou supprimer toutes les options contenant un pattern, c’est trop risqué.

Scénario B: entrée “bizarre” mais pas forcément active

Parfois, vous trouvez des valeurs suspectes, mais sans lien avec le comportement. Cela peut être un faux positif. Un plugin peut stocker un script d’analytics, ou un champ peut contenir un HTML normal.

Dans ce cas, la correction ne devrait pas être automatique. Je procède généralement comme suit:

image

    je teste une page liée à l’entrée, après suppression ponctuelle, je compare le rendu, je surveille les redirections et les chargements externes.

Si l’anomalie disparaît, vous confirmez que l’entrée était liée.

Scénario C: entrée trop large à traiter comme un cas isolé

Dans certains incidents, la compromission a un “pivot”. Par exemple, une option unique contient un code ou un modèle qui injecte ensuite des contenus. Si vous supprimez une meta sans corriger le pivot, l’injection revient.

Ici, la correction doit viser l’élément de contrôle. C’est un choix d’ingénierie: vous identifiez ce qui déclenche, pas seulement ce qui affiche les symptômes.

Le moment où wp_options devient critique: “reset” prudent

J’insiste là dessus: ne faites pas de “reset” global de wp_options. Sur un site avec cache, transients, réglages de plugins, et options de thèmes, vous pouvez casser des fonctionnalités.

Ce que j’ai vu fonctionner, en revanche, c’est une stratégie de nettoyage ciblée: retirer uniquement des clés suspectes ou restaurer des valeurs connues.

Un indicateur utile: si vous avez accès à la configuration saine (par exemple, une sauvegarde d’avant incident, ou un clone d’avant la compromission), vous pouvez comparer.

Sans comparaison, la méthode “suppression par patterns” peut marcher, mais elle demande un cycle de test. Dans un incident de production, ce cycle est pénible. L’idéal reste la comparaison avec une sauvegarde antérieure.

wp_postmeta: nettoyer sans détruire les contenus réels

Dans wp_postmeta, on peut avoir une tentation: supprimer toutes les meta associées aux pages touchées. C’est efficace, mais ça peut aussi supprimer des champs ACF, SEO, ou des paramètres de thème.

La bonne approche est de supprimer uniquement des meta key suspectes, ou des metavalue explicitement malveillants.

Concrètement, quand je cible wp_postmeta, je fais attention à deux choses:

    Certaines meta_key sont “utiles” et peuvent contenir du HTML. Certaines meta_key sont spécifiques à un plugin, et leur absence peut casser des affichages ou des réglages.

Donc je privilégie la correction de la valeur, ou la suppression de la meta key précise, plutôt que la suppression de toutes les métas d’un postid.

Si vous découvrez une meta_key qui semble nouvelle et qui n’appartient pas à votre environnement habituel, c’est souvent elle la cible.

Cas pratique: une injection qui persiste après correction des fichiers

Je vous raconte un scénario réel, anonymisé. Le site affichait des blocs ajoutés en bas de pages, parfois avec une redirection discrète. Les fichiers PHP modifiés existaient, oui, mais après nettoyage de ceux-ci, le problème revenait quelques minutes plus tard.

Le pivot était dans wp_options: une entrée stockait un fragment injecté, utilisé par un thème modifié, et qui reconstituait l’effet dès qu’une requête se produisait.

Le correctif a été fait en deux temps:

    suppression de l’option suspecte dans wp_options, suppression ou correction des meta reliées dans wp_postmeta sur les pages ciblées.

Ce qui a évité une boucle de “chat et souris”, c’est l’idée suivante: si l’injection persiste après avoir retiré les fichiers, regardez la base. Et si elle persiste après suppression des méta pages, regardez les options globales.

Vérification après correction: comment être sûr que vous avez réellement nettoyé

Après correction, vous devez vérifier sans vous contenter du “ça a l’air normal”.

Je recommande une vérification en trois axes:

Tests sur les pages touchées: rechargement, navigation, vérification du comportement (redirection, contenu injecté). Vérification des pages d’administration: vous ne voulez pas d’un retour d’exécution via un autre chemin. Surveillance des requêtes externes: si votre navigateur ou un outil de dev montre des appels vers des domaines inattendus, c’est un signal à traiter.

Si vous avez accès à des logs (serveur, CDN, firewall applicatif), regardez les patterns d’accès. Une injection réactive souvent des mêmes endpoints ou des même paramètres.

Ce que je fais aussi, quand c’est possible: je compare le comportement sur une session “propre”, par exemple en navigation privée. Ça réduit le risque de confondre un cache côté navigateur avec la réalité.

Sécuriser ensuite, sinon vous nettoyez sans fin

Nettoyer wp options et wppostmeta est la phase “chirurgicale”. Mais si la compromission initiale venait d’un accès illégitime, d’un plugin vulnérable ou de mots de passe faibles, vous allez retomber.

Une bonne sécurité post-incident repose sur trois leviers:

    réviser la chaîne d’accès: comptes admin, rôles, et éventuellement suppression des comptes inutiles, mettre à jour le cœur WordPress, les thèmes et plugins, renforcer les contrôles d’intégrité et la politique d’accès (mots de passe, 2FA si disponible, limitation des tentatives).

Je n’insiste pas sur des slogans. Sur le terrain, les incidents reviennent surtout quand une même faille reste ouverte.

Checklist de validation ciblée (sans basculer tout le système)

Voici la courte liste que j’utilise pour décider si la correction sur wp options et wppostmeta tient la route.

    Comparer les entrées suspectes supprimées avec ce qui reste, et vérifier que les clés ne reviennent pas. Tester 2 à 5 pages qui montraient l’injection, sur session privée et avec cache vidé. Vérifier l’administration: connexion, affichage des menus, et pages de création ou modification. Contrôler les sources: scripts et liens externes inattendus dans le HTML rendu. Relancer un scan de fichiers (au moins un inventaire des modifications récentes) et s’assurer qu’aucun plugin ou thème n’a été re-modifié.

Si trois de ces points échouent, on ne “termine” pas, on repart en analyse.

Quand faut-il aller plus loin que la base?

Parfois, le problème ne vient pas uniquement de wp options et wppostmeta. Il peut y avoir:

    un fichier PHP modifié dans le thème ou dans un plugin, une webshell déposée ailleurs, une modification sur le chargement d’un hook (fichiers que WordPress exécute à chaque requête), un point d’entrée via des formulaires.

La base est alors un symptôme et une persistance. C’est pour ça que je conseille de traiter ces corrections avec un angle plus large: base et fichiers doivent être cohérents. Si vous nettoyez la base, mais que vous laissez une webshell capable de re-injecter des données, vous reverrez les mêmes https://gardewp.fr/nettoyage-malware-wordpress/ artefacts.

C’est souvent là que le temps disparaît, car les équipes s’acharnent sur la base en oubliant l’accès.

Edge cases: préfixes, multisite, et tables différentes

Trois cas peuvent compliquer la démarche:

    Si votre site utilise un préfixe non standard (pas wp_), ajustez vos requêtes. Sinon vous risquez de “nettoyer” la mauvaise base de table. En multisite, les tables peuvent inclure plusieurs bases ou des préfixes, et les métadonnées peuvent être dispersées. Une correction localisée peut ne pas suffire si la charge est portée sur un sous-site. Certains plugins créent beaucoup de données dans wp options ou wppostmeta. Sans comparaison, vous pouvez confondre normal et anormal.

Dans ces cas, je reviens à la méthode comparative: sauvegarde antérieure, ou copie saine du site, ou au minimum comparaison avec un site similaire non infecté si c’est votre cas.

Stratégie de travail recommandée si vous avez peu de temps

Si vous êtes sous pression, vous voulez un chemin qui réduit le risque tout en allant vite.

Sans faire de liste trop longue, l’idée est simple: ciblez d’abord le “pivot” le plus probable. En pratique, je commence souvent par wp options pour trouver une clé globale suspecte, puis je descends dans wppostmeta pour corriger uniquement les pages concernées.

Ensuite, je vérifie. Et si le comportement persiste, je réoriente vers les fichiers et le déclencheur.

Je l’ai déjà dit autrement, mais je le redis parce que c’est une leçon utile: nettoyer au hasard dans la base, c’est le plus long chemin. Nettoyer de façon ciblée, puis valider, c’est le plus rapide.

Pour aller plus loin: réduire la récurrence des incidents

Après un incident, la question n’est plus “comment nettoyer”, elle devient “comment éviter que ça revienne”. Dans WordPress, ça passe par une discipline de maintenance.

Le cœur de la discipline, c’est la réduction de surface d’attaque. Moins vous avez de plugins inutiles, moins vous avez de points d’entrée potentiels. Et plus vos mises à jour sont régulières, moins vous restez exposé à des vulnérabilités connues.

Côté base, vous pouvez aussi planifier une routine de vérification:

    garder des sauvegardes régulières, surveiller les changements anormaux dans la base, maintenir un processus pour comparer une sauvegarde saine avec l’état actuel en cas d’alerte.

Ce n’est pas une garantie absolue, mais c’est ce qui transforme une réponse en incident en capacité de résilience.

Nettoyer un WordPress infecté en corrigeant wp options et wppostmeta demande de la méthode, pas seulement du “nettoyage”. Si vous vous concentrez sur la persistance, le pivot, et les valeurs réellement incohérentes, vous réduisez le risque de casser un fonctionnement légitime. Et surtout, vous gagnez en certitude: le site ne redevient pas bon “par hasard”, il redevient bon parce que vous avez neutralisé les éléments qui pilotent l’injection.