Quand une intrusion vise WordPress, les traces ne se limitent presque jamais au site “tel qu’on le voit”. Les attaquants cherchent aussi à persister, à masquer leurs modifications et à accélérer le retour d’un contenu piégé. Parmi les mécanismes les plus utilisés, il y a la manipulation du cache et des transients. Même après avoir nettoyé les fichiers corrompus et réinstallé des thèmes ou des plugins, on peut continuer à afficher un contenu malveillant si des données injectées ont été stockées dans wp_options, dans un cache d’objets, ou encore dans une couche intermédiaire (cache navigateur, CDN, reverse proxy).
Dans ce billet, je parle de désinfection WordPress centrée sur un point souvent sous-estimé : supprimer les données de cache et les transients injectés, sans casser le site au passage. L’idée n’est pas de “tout effacer à l’aveugle”, mais de viser ce qui peut contenir de la persistance côté base de données et, ensuite, de pousser une purge propre côté couches externes.
Comprendre pourquoi le cache relance l’infection
Sur WordPress, les transients sont une forme de mise en cache stockée dans la base de données, dans la table wp_options. Ils sont pratiques pour accélérer des calculs coûteux, mais ils sont aussi un emplacement logique pour garder une “donnée utile” après une compromission.
Deux scénarios reviennent souvent en désinfection :
1) Le site charge une page “correcte” car les fichiers ont été nettoyés, mais un contenu injecté a été mis en cache via transient. Le visitor reçoit encore le mauvais texte, la mauvaise bannière, ou un redoutable script en différé.
2) L’attaquant a déposé un mécanisme qui repopule le cache au prochain chargement. Si on supprime seulement les fichiers et pas les transients, il suffit parfois d’une requête ou d’un trafic normal pour que les données reviennent.
Le cache n’est donc pas seulement une question de performance. C’est un vecteur de rémanence. Et il faut s’en méfier particulièrement quand le site a été compromis via un plugin vulnérable, un thème modifié, ou une faille d’accès à l’administration.
Le point de départ indispensable : savoir ce qui a été manipulé
Avant de toucher à la base, j’utilise une règle simple : ne pas “purger” tout sans contexte. En pratique, je commence par trois observations, parce qu’elles orientent la stratégie.
D’abord, est-ce que le contenu malveillant s’affiche même quand on change d’agent utilisateur, quand on ouvre en navigation privée, ou quand on désactive le cache navigateur ? Si oui, c’est un signal fort que la source est côté serveur ou dans un cache partagé.
Ensuite, est-ce que le problème se déclenche sur certaines pages uniquement (par exemple pages produits, pages catégorie, page d’accueil) ? Si oui, ça pointe vers une donnée calculée et mise en cache, souvent liée à des transients ou à un cache d’objets.
Enfin, quel est le stack de cache en place ? Il peut y avoir un plugin de cache (W3 Total Cache, WP Rocket, LiteSpeed Cache), un cache d’objet (Redis via plugin), un CDN, un reverse proxy, ou même un cache côté hébergeur. Les purges doivent être coordonnées, sinon on laisse derrière soi une couche qui continue de servir l’ancienne version.
Les emplacements à surveiller pendant la désinfection WordPress
Côté WordPress, les emplacements les plus typiques sont les suivants.
1) wp_options : transients et caches applicatifs
Les transients portent souvent des préfixes reconnaissables, par exemple transient_ et timeout_ en interne. Concrètement, pour un transient mon_cle, WordPress utilise deux entrées :
- une entrée de clé mon_cle une entrée de timeout mon_cle_timeout
En base, les lignes sont dans wp_options avec option_name contenant ces clés.
Après une intrusion, on voit parfois des transients “non standards” créés par du code injecté : clés longues, préfixes bizarres, ou valeurs contenant des fragments HTML, du JavaScript, ou des URLs inattendues. La suppression de ces transients est l’une des étapes les plus efficaces pour stopper une persistance discrète.
2) Cache d’objets : Redis, Memcached, ou persistent object cache
Si le site utilise un cache d’objets persistent (Redis, Memcached, ou plugin équivalent), il peut garder des résultats calculés. Dans ce cas, même si les transients sont supprimés dans la base, un ancien état peut subsister dans le cache d’objets selon la configuration.
Le risque, c’est le décalage entre “ce que la base contient” et “ce que WordPress croit contenir” en lisant le cache d’objets. D’où la nécessité de purger aussi cette couche.
3) Cache de page et cache navigateur/CDN
Un plugin de cache de page stocke souvent des versions HTML complètes. Une CDN peut aussi servir une version figée. Même si la logique serveur est nettoyée, le monde extérieur continue d’obtenir l’ancienne page si la purge n’a pas lieu.
Je l’ai vu sur un site où l’infection semblait “revenant” toutes les heures. Les fichiers avaient été corrigés, mais le cache de page et le cache CDN n’étaient pas purgés, et un rule automatique sur le CDN réutilisait des contenus stockés. Tant qu’on n’a pas purge au bon niveau, la désinfection donnait l’impression d’être incomplète.
Stratégie de nettoyage : ordre et prudence
Le meilleur ordre dépend de votre contexte, mais j’utilise une logique robuste : d’abord supprimer les sources de persistance dans la base, puis purger le cache d’objets, puis purger les caches de page et les couches externes.
Cette approche réduit le risque de repopulation immédiate. Si vous purgez les couches externes trop tôt, vous pouvez simplement provoquer une recréation des données injectées par un mécanisme encore présent.
L’autre point de prudence, c’est la quantité. Effacer “tous les transients” sans réflexion peut ralentir le site au redémarrage le temps de regénérer les caches, et ça peut aussi déclencher des effets de bord. Dans une désinfection, c’est parfois acceptable, mais il faut être conscient de la trade-off.
Vérifier la présence de transients injectés (sans casser la prod)
Si vous avez accès à la base via https://gardewp.fr/nettoyage-malware-wordpress/ phpMyAdmin, Adminer, ou un client MySQL, vous pouvez inspecter wp_options pour repérer des clés anormales.
Une méthode pragmatique consiste à chercher des éléments qui ne devraient pas être présents :
- chaînes qui ressemblent à des scripts ou à du HTML des URLs qui ne font pas partie du domaine légitime des clés dont le préfixe n’est pas typique de vos plugins
Dans un incident, j’ai déjà vu des transients dont la valeur contenait des blocs HTML avec des attributs et une URL étrangère. Le transient portait une clé qui ressemblait à une signature (pas à un nom standard de plugin). La simple suppression de ces entrées a stoppé le rendu malveillant, alors même que le code des fichiers avait été réinstallé depuis la veille.
Si vous ne savez pas quoi chercher, vous pouvez aussi vous appuyer sur la comparaison. Par exemple, exportez les lignes de wp_options concernées avant suppression (même un extrait), puis regardez les différences après nettoyage. Ce n’est pas “joli”, mais c’est fiable.
Supprimer les transients et caches injectés : options réalistes
Il y a plusieurs façons de supprimer ces données. Le bon choix dépend de vos outils et de la taille de la base.
Option A : suppression ciblée côté base
C’est la méthode la plus précise. Vous supprimez seulement les transients suspectés (ou ceux identifiés par préfixe et contenu).
Avantages :
- moins de régénération massive impact plus faible sur le comportement du site
Inconvénients :
- nécessite une phase d’enquête demande de connaître les clés
Ici, je recommande de travailler sur wp_options en ciblant option_name correspondant aux transients. Une prudence simple : ne supprimez pas des clés qui appartiennent clairement au cœur de WordPress ou à des composants légitimes, surtout si vous n’avez pas confirmé le caractère suspect.
Option B : purge complète des transients
Quand le site a été fortement touché, ou quand l’enquête ne mène à aucune clé évidente, certains administrateurs préfèrent effacer tous les transients.
Avantages :
- rapide, simple à appliquer réduit drastiquement le risque qu’un transient injecté reste actif
Inconvénients :
- régénération de caches, parfois visible comme une montée de charge au prochain passage dans certains cas, des plugins peuvent relancer des calculs lourds
Dans une désinfection WordPress, ça peut être un choix raisonnable, surtout sur un site à faible volume. Sur une infrastructure très chargée, je préfère une purge plus ciblée.
Option C : suppression via plugin utilitaire (si vous en utilisez déjà)
Il existe des plugins qui permettent de “vider le cache” ou de “supprimer les transients”. Le problème, c’est la confiance. En cas d’infection, vous ne voulez pas ajouter d’outil que vous n’avez pas validé, surtout si vous ne savez pas qui l’administre et comment il s’exécute.
Si vous utilisez déjà un plugin de purge de transients éprouvé dans votre stack, et que son code n’a pas été touché, c’est une voie possible. Sinon, je préfère revenir à une suppression en base, c’est plus direct et plus contrôlable.
Ne pas oublier le cache d’objets (Redis, Memcached, persistent object cache)
Supprimer les transients dans wp_options ne suffit pas si un cache d’objets persistant continue de servir des résultats.
Concrètement, si Redis est configuré comme backend, la purge doit idéalement être réalisée côté serveur Redis ou via le mécanisme prévu par votre plugin de cache d’objet.
Le piège classique : faire une purge côté WordPress, constater que le cache “semble nettoyé”, puis découvrir que le site continue à servir une page figée ou des données calculées plus tôt. En désinfection, ce décalage se traduit par “ça revient”, alors qu’en réalité ce n’est pas revenu depuis la base, c’est resté dans le cache d’objets.
Selon la configuration, vous pouvez être tenté de faire un flush complet Redis. Je ne le conseille pas sans connaître la portée. Un Redis peut héberger d’autres clés pour d’autres sites sur la même instance. Flusher à blanc peut créer une charge de régénération ailleurs, ou casser une autre application.
Le bon geste consiste à purger le préfixe WordPress (ou le namespace dédié) si c’est possible. Si ce n’est pas possible, vous devez au moins vérifier quel est l’usage de Redis sur votre infrastructure.
Purger le cache de page et les caches externes
Une fois la partie persistante interne nettoyée, vous passez à l’effacement des couches qui stockent du HTML.
Selon les outils en place, la purge se fait de différentes manières :
- purge du plugin de cache de page (stockage et régénération) purge du CDN (et parfois purge “par URL” plutôt que globale) purge éventuelle d’un reverse proxy ou du cache hébergeur vidage des caches applicatifs (par exemple Varnish) si c’est présent
Je fais attention à la cohérence : si vous supprimez les transients, puis vous purgez le cache de page, mais que le CDN sert encore une ancienne version, le front reste faux. C’est frustrant, et ça fait perdre du temps à relancer la désinfection alors que la cause est juste un niveau de cache pas purge.
Mini-plan d’action concret (tout en restant prudent)
Voici un déroulé que j’applique généralement dans un incident, sans prétendre que c’est la seule méthode valable. Le but est de minimiser la probabilité de repopulation immédiate.
Mettre le site en mode maintenance si nécessaire, ou au minimum limiter temporairement le trafic le temps des suppressions sensibles. Identifier les plugins de cache, de CDN, de cache d’objet, et les points d’accès à la base. Supprimer les transients et entrées wp_options suspectes, ou purger les transients selon le niveau d’incertitude. Purger le cache d’objets (Redis/Memcached) dans son périmètre. Purger le cache de page (WordPress + plugins) puis le CDN et les caches de l’infrastructure.Cette séquence n’est pas magique, mais elle suit une logique, base de données d’abord, puis mémoire et rendu figé.
Comment savoir si c’est vraiment nettoyé (et pas juste masqué)
Le test le plus utile n’est pas uniquement “est-ce que la page est correcte”. Je cherche des signaux qui indiquent que la persistance a été rompue.
Pendant une désinfection, je vérifie à la fois le rendu et la réapparition. Le piège, c’est de tomber sur un contenu qui “n’apparaît plus” parce que le cache de page a été purgé, mais que des transients malveillants sont encore présents. Le site peut redevenir piégé après un certain temps ou lors d’un recalcul de cache.
Je préfère faire des tests avec plusieurs fenêtres :
- navigation privée pour éviter le cache navigateur test sur une URL qui déclenche souvent la logique mise en cache vérification après un délai raisonnable, par exemple quelques minutes, pour laisser le recalcul se produire
Si vous avez un outil d’analyse de réponse HTTP, cherchez aussi des indices. Un en-tête qui montre que le contenu vient d’un cache (CDN) peut expliquer pourquoi vous voyez encore “l’ancienne version”.
Points d’attention : risques, effets de bord et cas limites
Effacer trop, trop vite
Purger tous les transients peut faire remonter la charge au moment où WordPress régénère des données. Sur un site assez petit, ce n’est pas un souci. Sur un site à trafic réel, c’est un point de pilotage.
Si vous devez purger massivement, faites-le pendant une fenêtre où la charge est tolérable. Sur certains hébergeurs, une purge massive peut déclencher une régénération simultanée, et donc des pics.
Le mécanisme d’injection reste en place
Si les transients sont injectés par un code encore actif dans un plugin ou un thème, supprimer les transients ne fera que retarder l’apparition. En clair, le “nettoyage du cache” n’est pas une désinfection complète.
C’est pour cela que je considère cette démarche comme une couche de finition, après avoir retiré la modification de fichiers et stoppé la faille. Le cache et les transients sont une persistance, mais ils ne remplacent pas la suppression de la cause.
Droit d’accès et cohérence des permissions
Une désinfection implique parfois des modifications de droits. Si le site repasse dans un état où WordPress ne peut pas écrire ou lire certains caches, vous pouvez vous retrouver avec un site instable. Ce n’est pas directement lié aux transients injectés, mais ça survient en même temps dans beaucoup d’incidents.
Multi-sites
En WordPress multisite, les transients et options peuvent être stockés à des niveaux différents. Ne supposez pas que tout est au même endroit. En cas de multisite, vérifiez les contextes d’options.
Deux raccourcis utiles quand vous manquez de temps
Parfois, vous êtes face à un incident “urgent” et vous devez stabiliser rapidement. Deux approches peuvent aider à réduire le temps de diagnostic.
La première, c’est de commencer par la purge la plus probable : transients dans wp_options, puis purge cache d’objet et cache de page. Cette séquence traite les causes les plus fréquentes de réapparition du contenu, sans toucher d’abord aux fichiers.
La seconde, c’est d’utiliser des tests de rendu avant et après chaque purge, plutôt que de tout faire en une fois. Ça vous permet d’identifier la couche responsable. Si le contenu s’améliore après suppression des transients mais revient après une période, vous tenez un indice fort sur la persistance.
Checklist finale de validation (après purge et désinfection)
Une fois la purge faite, j’aime bien valider en mode “zéro supposition”. Voici une checklist courte, conçue pour détecter la persistance.

- Vérifier les pages “sensibles” en navigation privée et sur un mobile Contrôler les URL qui déclenchent souvent des contenus mis en cache Confirmer que le contenu ne revient pas après une courte temporisation (quelques minutes) Tester que les plugins de cache et d’objet n’ont pas de réglage qui recharge un contenu ancien Surveiller les logs applicatifs et erreurs pendant les premières heures
Cinq points, pas plus. L’objectif, c’est de confirmer que le système ne recrée pas les données injectées.
Ce que j’aurais aimé savoir plus tôt (petite expérience terrain)
Sur un incident récent, le site “semblait” propre après réinstallation de thèmes et suppression de fichiers suspects. Le front affichait un contenu normal pendant quelques minutes, puis un bloc publicitaire et un script de tracking étrange réapparaissaient sur la page d’accueil. Au début, on suspectait un plugin encore compromis.
Le diagnostic s’est fait en regardant ce qui était en cache côté base. Les transients contenaient déjà le HTML récupéré et reconstitué au chargement, comme si un script attendait juste la purge pour se réactiver. Une fois les transients supprimés et le cache d’objets purgé, le comportement est devenu stable. Le plugin semblait “intact” au sens fichier, mais sa logique restait associée à des données persistées. C’est là que la purge de transients prend tout son sens en désinfection WordPress.
Conclusion implicite : cache et transients, ce n’est pas secondaire
Pour beaucoup d’équipes, l’étape “désinfection WordPress” ressemble à une opération de nettoyage de fichiers et de revalidation de plugins. C’est indispensable, mais pas suffisant. Le cache et les transients sont des zones où l’infection peut continuer à vivre, surtout quand le code malveillant a déjà réussi à préparer des données.
Quand vous supprimez les transients injectés, que vous purgez le cache d’objets et que vous réalignez le cache de page, vous coupez les chemins de réapparition les plus fréquents. Et surtout, vous arrêtez ce moment frustrant où “tout est propre”, mais le site continue de montrer l’ancienne réalité.
Si vous voulez, dites-moi votre configuration (type de plugin de cache, Redis ou non, CDN éventuel, site simple ou multisite). Je peux vous proposer une stratégie de purge plus précise, centrée sur les transients et sur les couches exactes présentes chez vous.