Un thème ou un plugin compromis ne ressemble pas toujours à un “piratage spectaculaire”. Bien souvent, il s’agit d’un détail discret: un fichier modifié, une fonction ajoutée quelque part dans les entrailles de WordPress, un chargement de script externe en douce, ou une redirection qui ne se manifeste que pour certains navigateurs, certaines plages horaires, ou certains pays. Et parce que WordPress charge beaucoup d’éléments dynamiquement, le site peut continuer à fonctionner… tout en laissant passer une compromission.
L’objectif ici n’est pas de “deviner” à l’odeur, mais de vérifier avec méthode si votre thème ou votre plugin a été touché. Je vais vous montrer comment raisonner, quoi contrôler en priorité, et comment interpréter les signaux. Vous aurez aussi des garde-fous, parce qu’une vérification trop agressive peut casser votre site ou vous faire perdre des traces utiles.
Les signaux qui doivent vous mettre la puce à l’oreille
Avant de toucher au code, j’aime commencer par le contexte. Un thème ou un plugin compromis apparaît rarement sans raison. Parfois, c’est la suite logique d’une installation atypique, d’une mise à jour mal faite, ou d’un compte administrateur qui a été utilisé depuis un nouvel endroit. D’autres fois, c’est un symptôme que l’on remarque avant même de penser “malware”.
Voici des exemples réalistes, vécus dans le cadre de nettoyages: un site WordPress infecté qui affiche soudainement une bannière d’erreur ou des pop-ups sur certaines pages, des formulaires qui envoient des données à une URL inconnue, un trafic qui explose sur des pages invisibles pour l’utilisateur “normal”, ou encore une vitesse qui chute dès qu’un plugin spécifique est activé.
Les signaux techniques sont parfois plus parlants que les plaintes visibles. Un fichier qui contient des fonctions de déchiffrement “bizarres”, une suite de caractères encodés, des références à des domaines fraîchement créés, ou des appels à des scripts externes depuis le front-end sont des pistes sérieuses. Il ne faut pas confondre ces cas avec un plugin légitime qui charge des ressources tierces, ni avec un système de tracking cohérent. La différence se joue souvent dans le “comment” et le “où” exactement.
Un point important: une compromission peut ne pas être permanente. Certains codes malveillants ne s’exécutent que si des conditions sont remplies, par exemple si la requête vient d’un navigateur précis, ou si la page demandée correspond à une liste de chemins. C’est pour cela qu’un site peut “avoir l’air correct” pendant une partie du test, puis révéler le problème lors d’une autre navigation.
Partir des faits: ce que vous pouvez observer sans toucher au site
Avant d’ouvrir votre éditeur, faites une observation structurée. Vous cherchez des preuves, pas seulement un ressenti.
1) Regarder ce qui change au niveau du navigateur
Si vous suspectez un thème ou un plugin, commencez par comparer les pages. Des différences nettes entre deux pages “proches” sont souvent révélatrices. Par exemple, une page d’accueil normale et une page de catégorie qui injecte un script inconnu, ou un article qui déclenche une redirection mais pas les autres.2) Vérifier si des scripts externes apparaissent
Dans les outils développeur du navigateur, examinez l’onglet Réseau et le DOM. Si un script est chargé depuis un domaine qui n’a rien à faire là, notez le nom du fichier, l’URL, et la page où cela se produit. Ce détail vous aidera ensuite à retrouver dans WordPress le moment exact où le script est ajouté.
3) Considérer le “timing”
Des attaques basées sur des horloges ou des flux conditionnels peuvent exécuter du code à certaines heures. Si vous ne voyez rien à 10 h mais que ça apparaît à 17 h, c’est un indice. De même, si le problème ne se produit que pour mobile ou que pour une géolocalisation, vous avez un bon axe d’investigation.4) Utiliser les signaux serveurs
Sans sortir du cadre WordPress, regardez côté hébergement: logs d’accès, erreurs 404 inhabituelles, pics d’URL qui ne correspondent à aucun contenu publié. Sur certains dossiers, vous pouvez voir des requêtes qui ne “collent” pas à votre trafic normal.À ce stade, vous n’avez pas encore besoin de prouver que c’est un thème ou un plugin. Vous cherchez des indices qui vont guider votre recherche. C’est là que beaucoup de projets perdent du temps, car ils commencent directement par “désactiver tout”, puis ils ne savent plus quoi comparer.
Une méthode d’isolation: distinguer thème, plugin, et configuration
WordPress est un écosystème. Même si un script malveillant est injecté par un plugin, il peut dépendre d’une configuration, d’un champ de base de données ou d’un hook d’un thème. L’inverse est aussi vrai: un thème compromis peut appeler des fonctions de plugin, ce qui complique l’analyse.
La stratégie la plus robuste consiste à isoler progressivement.
Le principe est simple: vous voulez réduire la surface d’exécution jusqu’à retrouver la cause. Désactiver un plugin et tout recharger peut montrer que le problème disparaît, mais parfois la base de données contient encore des traces, ou le thème continue d’appeler le code.
Dans la pratique, il est utile de raisonner en niveaux:
- niveau front-end: injection de scripts, modifications de contenu rendu; niveau hooks WordPress: actions et filtres impliqués; niveau fichiers: ajout de code dans PHP, modifications de templates; niveau données: options, postmeta, menus, shortcodes.
Sans vouloir transformer cette vérification en enquête judiciaire complète, vous gagnerez en fiabilité en combinant plusieurs niveaux.
D’abord, vérifiez l’intégrité des fichiers: l’étape qui évite les faux positifs
Quand on me dit “je pense que mon plugin est compromis”, je commence souvent par “avez-vous comparé vos fichiers à l’original?”. Parce que la compromission se traduit très souvent par une altération du code. Même si un attaquant ne modifie pas énormément, il laisse des signatures: changements subtils dans un fichier PHP, ajouts dans un include, présence de code encodé, ou appels à des fonctions natives de manière inhabituelle.
Concrètement, vous pouvez vérifier:
- si la version installée correspond à la version réellement attendue; si les fichiers ont des dates de modification suspectes, notamment juste après un événement d’authentification ou une mise à jour; si des fichiers inattendus sont présents dans les répertoires du thème ou du plugin.
Les faux positifs existent. Un thème peut intégrer une librairie tierce, ou un plugin peut contenir des lignes qui paraissent “codées” parce qu’il fait du minify pour un fichier de config. Le bon réflexe est de comparer à la version distribuée par l’éditeur du plugin ou du thème, ou à une sauvegarde connue saine.
Si vous n’avez pas de référence exacte, vous pouvez tout de même faire une comparaison relative entre ce qui est présent maintenant et ce qui est habituellement distribué. L’important est d’identifier des différences réelles, pas de s’arrêter à “ça sent mauvais”.
Identifier les injections au rendu: ce que vous devriez chercher dans le HTML et dans les hooks
Une compromission “typique” injecte du code au moment où WordPress rend la page. Cela peut se produire dans un template du thème, dans des hooks comme wp head ou wpfooter, ou via un enqueuing de scripts.
En inspectant le HTML rendu, vous pouvez remarquer des éléments:
- un script ajouté dans le head ou le footer; un iframe masqué ou un élément invisible; des attributs nouveaux sur des balises existantes; des redirections déclenchées par JavaScript.
Ensuite, retour au code: si vous identifiez l’URL d’un script injecté, vous pouvez chercher dans votre installation WordPress où cette URL apparaît. Faites une recherche dans tous les fichiers PHP des thèmes et plugins. Si vous ne trouvez pas l’URL, cherchez une partie unique du code: un identifiant, un nom de fonction, une chaîne encodée, ou un motif.
Un détail crucial: certaines charges ne contiennent pas l’URL en clair, elles sont transformées. Vous verrez alors des chaînes longues et encodées. Dans ce cas, la recherche “simple” peut échouer. Vous pouvez repérer des motifs d’obfuscation: base64 decode, gzinflate, strrot13, eval, preg_replace avec le modificateur e, ou des boucles qui assemblent des morceaux de code.
Je reste prudent ici. L’utilisation d’une fonction comme base64_decode n’est pas automatiquement malveillante. Certains plugins ou thèmes utilisent base64 pour stocker une config, ou pour embarquer une ressource. Ce qui compte est le contexte exact: si la chaîne est suivie d’un eval, d’un appel à une requête HTTP, ou d’un affichage de script, la probabilité monte.
Vérifier directement les thèmes et plugins: contrôle “par répertoires” et attention aux fichiers “anormaux”
Quand vous soupçonnez un thème, examinez particulièrement:
- le dossier du thème, surtout les fichiers PHP principaux (index, header, footer, functions); les fichiers qui ne correspondent pas à une structure standard du thème; les includes ou fichiers appelés dynamiquement.
Pour les plugins, vérifiez:
- le fichier principal du plugin (souvent le plugin.php ou un fichier avec le même nom que le dossier); les fichiers “autoload” ou “init” si le plugin en a; les dossiers où des scripts additionnels sont ajoutés.
Le piège le plus fréquent est de se focaliser sur “le plugin qui fait du script”. Une attaque peut modifier un plugin technique qui n’a l’air de rien. Par exemple, un plugin d’optimisation ou de sécurité peut être utilisé comme vecteur, ou au contraire un plugin de cache peut servir à masquer la charge.
Un autre piège est la dépendance croisée: un plugin peut sembler sain, mais il exécute une charge qui vient du thème. Si vous isolez un plugin sans isoler le thème, vous pouvez conclure trop vite.
Le levier le plus utile: désactiver en sécurité, puis activer par étapes
Isoler fonctionne très bien, à condition de le faire proprement. Le but est d’arriver à une situation où le problème disparaît, puis de le réintroduire en activant progressivement.
Avant toute chose, pensez à la sécurité opérationnelle. Si votre site est compromis, manipuler des fichiers peut accentuer le risque, surtout si vous vous connectez en mode standard alors que le compte est possiblement exposé. Si vous pouvez, travaillez via un environnement de staging ou au minimum en maintenance, idéalement après avoir pris une sauvegarde complète.
Dans WordPress, vous pouvez désactiver des plugins. Si le site ne répond pas correctement, l’approche peut nécessiter une intervention côté serveur (selon votre hébergement). L’idée est de pouvoir restaurer une base saine sans perdre vos preuves.
Voici une manière de procéder, simple et efficace, sans transformer ça en process lourd.
Checklist pratique pour isoler la source (thème ou plugin)
- Prenez une sauvegarde complète (fichiers et base de données). Passez le site en mode de maintenance si nécessaire, puis observez ce qui change. Désactivez tous les plugins, puis vérifiez le rendu et les scripts chargés. Réactivez les plugins un par un (ou par lots), en contrôlant à chaque étape. Si le problème persiste après la désactivation des plugins, testez avec un thème par défaut.
Cette checklist marche parce qu’elle découple les couches. Si le problème disparaît avec tous les plugins désactivés, vous savez déjà que le vecteur est un plugin. Si le problème persiste, le thème, la configuration ou une partie “core” reste en lice.
Notez aussi les cas limites: certains thèmes ajoutent du code via des formulaires spécifiques, ou des plugins “anciens” qui ont encore des traces en base. Donc, quand vous réactivez, surveillez aussi les pages où la charge apparaît.
Inspecter le code avec lucidité: où regarder dans PHP quand ça “sent” l’obfuscation
Quand vous trouvez du code suspect dans un fichier de thème ou de plugin, votre travail est de comprendre le chemin d’exécution. Je recommande rarement de commencer par “supprimer des lignes au hasard”. Souvent, vous cassez le site, et vous perdez le contexte utile.
Ce que je cherche, c’est un triptyque:
1) Le point d’entrée
Qu’est-ce qui déclenche l’exécution? Un hook, une condition de page, un cron, une action d’admin, ou l’initialisation du plugin.2) La condition d’activation
Le code est-il conditionnel? Par exemple, un if avec $_SERVER, une vérification de rôle utilisateur, une analyse de user-agent, ou une condition sur l’URL demandée. Une compromission “discrète” s’enferme souvent dans ce type de filtre.3) La sortie
Que produit le code? Il affiche un script, il envoie une requête HTTP, il modifie une option, il ajoute une règle rewrite, ou il redirige.Si le code obfusqué finit par appeler wp remoteget (ou une fonction équivalente) vers un domaine externe, c’est un drapeau rouge. Si, en plus, le code reconstruit une chaîne de script JavaScript à injecter dans wp_head, la conclusion se rapproche.
Un cas délicat: certaines bibliothèques “minifiées” pour des performances peuvent ressembler à une charge, surtout quand vous voyez des suites longues. Dans ce scénario, vérifiez la présence de fonctions dangereuses. Je fais aussi attention aux variables et aux noms de fonctions. Un plugin propre utilise des noms cohérents, une structure claire. Un plugin compromis ajoute des utilitaires génériques, puis assemble des opérations sans logique produit.
Chercher dans la base de données: options, postmeta, shortcodes et menus
Parfois, le thème et le plugin ne sont pas les seuls coupables. Les compromis “persistants” enregistrent des instructions dans la base de données. WordPress peut ensuite exécuter ces instructions pendant le rendu.
Les endroits à inspecter en priorité, quand vous cherchez des traces de compromis, sont souvent:
- wp_options: options liées à la configuration du plugin, mais aussi des options inattendues; wp_postmeta: métadonnées de contenus qui peuvent stocker des scripts pour certains articles ou types de pages; shortcodes: si un shortcode a été ajouté ou modifié, il peut injecter du code lors de l’affichage; menus: certains compromis modifient des items de navigation pour déclencher un chargement externe.
Je reste volontairement sans donner une liste “exhaustive”, parce que chaque site a ses plugins et ses préfixes. Mais si vous trouvez une option avec une valeur longue et encodée, ou un postmeta contenant un marqueur de script, c’est une bonne piste.
Le point important: si vous remettez le thème et les plugins à zéro, mais que la base contient encore la charge, le problème peut revenir. C’est pour cela que l’isolation ne suffit pas toujours. Une compromission peut être stockée ailleurs que dans les fichiers.
Témoins secondaires: journaux, utilisateurs, et cohérence des versions
Même si votre sujet ici porte sur thème et plugin, une vérification sérieuse https://gardewp.fr/nettoyage-malware-wordpress/ ne s’arrête pas au code. Les compromis s’accompagnent souvent de traces sur l’authentification.
Regardez:

- nouveaux comptes admin ou comptes avec des rôles inattendus; sessions actives anormales; tentatives de connexion depuis des adresses inhabituelles; mise à jour de versions que vous n’avez pas lancées.
Sans en faire une enquête à la première personne, ces points vous donnent la chronologie. Si un plugin a été modifié à la minute près après une connexion depuis un lieu inconnu, c’est un indice fort.
Un exemple concret d’analyse: l’URL d’un script qui apparaît “de nulle part”
Imaginons que vous voyez dans le navigateur un script chargé depuis un domaine inconnu. Vous notez l’URL exacte, puis vous faites une recherche dans vos fichiers PHP pour retrouver ce fragment. Si vous trouvez une ligne ajoutée dans un fichier functions.php du thème, avec un add action sur wphead, vous tenez une piste solide.
Ensuite, vous examinez le fichier: la charge est-elle conditionnelle? Est-ce déclenché uniquement sur certaines pages, ou uniquement quand l’utilisateur n’est pas connecté? Est-ce que le script est assemblé depuis plusieurs morceaux? Si vous voyez base64_decode puis echo d’un script, vous êtes probablement face à une charge.
Le bon réflexe à ce stade est de ne pas seulement “enlever echo”. Remettez plutôt le fichier à une version saine si vous l’avez en sauvegarde. Si vous n’avez pas, comparez à la version du thème avant modification, ce qui peut nécessiter de récupérer le thème propre auprès de sa distribution officielle. Ensuite, nettoyez la base si nécessaire.
Ce type d’exemple montre pourquoi la vérification doit combiner rendu, recherche dans le code, et restauration à une version connue.
Comment interpréter les “faux coupables” et éviter de casser votre site
Il y a une souffrance récurrente dans les nettoyages: on suspecte un plugin, on le désinstalle, puis le site reste infecté. Ou pire, il ne s’affiche plus.
Quelques raisons classiques:
- le problème n’était pas le plugin lui-même, mais un hook déclenché dans le thème; la charge était dans la base, donc elle réapparaît même après changement de fichier; un plugin “sain” charge le script parce qu’il s’appuie sur un paramètre de configuration compromis; vous avez restauré un fichier de thème, mais un autre fichier dans la même arborescence reste modifié.
Ce que je fais pour limiter les dégâts, c’est une logique de restauration progressive. Si un fichier est suspect, je préfère le remplacer par une version identique connue. Si je n’ai pas de référence, je compare avec la version distribuée publiquement et je n’édite que ce qui doit l’être pour revenir à une base saine.
Deux approches complémentaires: comparaison à une version saine et analyse “comportementale”
La vérification la plus fiable combine deux méthodes:
- une comparaison statique, fichier par fichier, par rapport à une version saine; une analyse comportementale, en observant le rendu et les requêtes réseau.
La comparaison statique est utile pour repérer des ajouts de code, des obfuscations, des modifications. Mais elle peut manquer des charges déclenchées par des données en base. L’analyse comportementale, elle, met en évidence les effets visibles, mais elle peut manquer les détails si le code est extrêmement conditionnel.
Quand je dois décider où investir mon temps, je commence par ce qui a le plus de chances d’être corrélé à votre problème actuel: si vous observez une injection claire dans le head, la comparaison à une version saine sur functions.php et sur les plugins qui ajoutent des scripts est souvent rentable.
Outils et méthodes utiles, sans dépendre d’une “solution magique”
Il existe des scanners, des plugins de sécurité, et des suites d’analyse. Ils peuvent aider, mais ils ne remplacent pas la compréhension. Certains outils détectent des signatures connues, mais ratent des variations. D’autres donnent des alertes trop larges et produisent du bruit.
Où regarder en priorité (outils et sources)
- Comparer la liste installée (thèmes et plugins) avec vos versions attendues. Vérifier les modifications de fichiers (dates, taille, présence de nouveaux fichiers). Analyser le rendu navigateur pour identifier les scripts injectés. Rechercher dans les fichiers les chaînes suspectes (URL, fragments uniques, fonctions de base). Inspecter les options et postmeta liées aux comportements d’injection.
Même si vous utilisez un scanner, gardez le réflexe d’aller voir le code et la cause. Sinon, vous finissez avec un “clean” qui n’est pas forcément vrai.
Une stratégie de remédiation après vérification: restaurer sans réinfecter
Une fois que vous avez identifié le thème ou le plugin suspect, la question devient “que faire pour que ça ne revienne pas?”.
Sur le plan opérationnel, la réponse dépend de votre contexte:
- si le fichier est modifié, remettez-le à une version saine; si des données en base contiennent la charge, nettoyez-les; si un compte a été utilisé pour la compromission, révoquez et sécurisez l’accès; si vous avez un vecteur réseau (fichiers uploadés via un autre point faible), corrigez-le aussi.
Un piège courant: restaurer uniquement les fichiers. Ça peut fonctionner temporairement, puis réapparaître si la base a conservé l’injection. L’inverse existe aussi: nettoyer la base mais laisser des fichiers modifiés. Dans ce cas, l’injection reprend au prochain rendu.
Cas particuliers: multisites, thèmes enfant, et plugins “builder”
Le contrôle peut devenir plus délicat dans certaines configurations.
Sur WordPress multisites, les rôles et les emplacements de fichiers peuvent être différents, et certains paramètres sont gérés au niveau réseau. Un thème ou un plugin peut être activé à un niveau spécifique, ce qui explique pourquoi vous voyez le problème sur certains sites du réseau et pas d’autres.
Les thèmes enfant ajoutent une couche. Un thème enfant peut surcharger functions.php ou templates. Une compromission peut être dans le thème parent, mais se manifester via l’enfant. Ou l’inverse.
Les plugins de type “builder” (éditeur visuel) stockent parfois du contenu complexe dans des structures internes. Un code injecté peut se cacher dans ces structures, et donc ne pas être visible dans les templates classiques. Dans ce cas, votre analyse doit suivre le flux: du contenu stocké vers le rendu.
Ce que j’exigerais de vous avant de conclure “compromis”
Pour conclure proprement, je ne me contente pas d’un “ça a l’air suspect”. Je cherche une convergence de preuves:
- un fichier modifié (date ou différence avec version attendue); une exécution qui correspond à l’effet observé dans le navigateur; une URL ou une chaîne unique retrouvée dans le code; une disparition du problème quand on isole le composant concerné.
Quand ces éléments s’alignent, vous pouvez agir avec plus de certitude, ce qui réduit le risque de casser le site. Et surtout, vous diminuez la probabilité de laisser une bombe à retardement, une compromission qui se réactive plus tard.
Si vous êtes pressé: un plan rapide en pratique
Si vous devez avancer vite, sans faire une analyse parfaite, voici l’enchaînement pragmatique que je recommande souvent:
D’abord isoler avec la désactivation par étapes, puis identifier l’injection au rendu, ensuite remonter au code qui déclenche l’effet, et enfin restaurer à une version saine avant de nettoyer la base si besoin. Si votre site est déjà en production, la priorité reste la stabilité et la sécurité de l’accès.
Et gardez en tête un principe simple: un thème ou un plugin compromis n’est pas juste “un fichier”. C’est une chaîne. Pour éliminer le problème, vous devez casser le chaînon qui déclenche l’exécution, et vérifier qu’il n’y a pas de résidu dans les données.
Si vous voulez, décrivez-moi votre configuration (thème, plugins suspects ou récemment ajoutés, et surtout ce que vous voyez exactement dans le navigateur, par exemple l’URL d’un script injecté ou le type de redirection). Je peux vous aider à cibler les fichiers et les hooks à vérifier en premier, sans vous faire perdre des heures.