Sur WordPress, le “malware” ne ressemble pas toujours à un gros bloc de code. Souvent, il se présente comme un ajout discret dans l’ombre, un script de tracking qui n’était pas là hier, une balise injectée dans le , ou un bout de JavaScript “camouflé” pour charger autre chose une fois la page visible. Le plus déroutant, c’est que l’apparence peut rester normale, le site continue d’afficher le contenu, et pourtant l’infection avance: pages qui chargent des scripts tiers suspects, trafic qui semble gonfler, formulaires qui se comportent bizarrement, ou des navigateurs qui signalent des activités à risque.
Quand on parle de supprimer un malware WordPress, l’enjeu est double. Il faut nettoyer l’injection (souvent du tracking ou de la redirection), et il faut empêcher la réinfection. Une suppression “au hasard” des fichiers visibles ne suffit pas si la porte d’entrée reste ouverte, par exemple un accès administrateur que vous n’avez pas donné, un plugin oublié, ou un champ qui sert d’outil d’exfiltration.
Je vous décris une méthode réaliste, basée sur ce que j’ai déjà vu sur des sites infectés par injection de scripts, avec les pièges classiques et la manière de trancher quand plusieurs hypothèses sont possibles.
Ce que l’on appelle “script de tracking injecté” dans un cas réel
Le scénario le plus fréquent ressemble à ceci. Vous ouvrez une page, puis vous regardez le code source et vous constatez une différence par rapport à votre dépôt. Dans le HTML, on trouve une ou plusieurs balises ajoutées: script, iframe, parfois du code qui s’exécute après un DOMContentLoaded, ou du JavaScript qui charge une ressource externe.
Sur WordPress, ces injections apparaissent souvent via:
- un fichier PHP modifié (dans un thème, un plugin, ou un fichier “fourre-tout” caché), un hook comme wp_head ou wp_footer, une action déclenchée sur certaines pages uniquement (par exemple pages “contact”, “produits”, ou toutes les pages index), ou une chaîne de caractères dans une option ou un meta, que le site réinjecte ensuite dans le front.
Le tracking peut être “classique” en apparence, avec des variables globales et des identifiants, mais dès qu’un script a été inséré sans votre consentement, il faut considérer que c’est un vecteur. Parfois l’objectif n’est pas seulement d’analyser. Parfois c’est de rediriger, de déposer un cookie, de voler un jeton, ou d’ouvrir une fenêtre de nuisance. Même si vous limitez les symptômes, le risque reste tant que l’infection est en place.
Les signaux qui aident, sans vous faire confondre avec un plugin légitime
Avant de “nettoyer au scalpel”, je préfère confirmer que ce que vous voyez mérite vraiment une chasse à l’infection. Les faux positifs existent, parce que beaucoup de sites utilisent déjà du tracking, des tags marketing, des pixels publicitaires, des scripts de performance, ou des intégrations (GA, Matomo, tags partenaires). La différence, c’est le contrôle et l’origine.
Voici ce que j’observe le plus souvent sur des sites réellement compromis, comparé à un site propre:
- présence de ou d’ qui n’apparaissent pas dans vos fichiers versionnés, chargements externes vers des domaines qui ne font pas partie de votre liste habituelle, scripts “obfusqués” avec eval, atob, fromCharCode, chaînes encodées en base64 ou conditions étranges, insertions uniquement pour certains navigateurs ou geolocalisations, souvent via des tests sur la langue, l’URL, la résolution, ou des segments, code qui modifie le comportement du front, par exemple en redirigeant après clic, en surchargeant des événements, ou en injectant un élément invisible.
Si vous voyez un identifiant Google ou un tag marketing connu, mais que le script est chargé depuis votre propre source ou un gestionnaire que vous administrez, ce n’est pas forcément une infection. Par contre, si le script est ajoutée en dur dans vos pages sans raison, c’est un drapeau rouge.
La partie qui compte le plus: bloquer la réinfection avant de “tout casser”
Le nettoyage, c’est aussi une discipline. Si vous supprimez un fichier modifié mais que l’infection a laissé un point d’entrée actif, vous aurez la même addition le lendemain, parfois dans une autre page ou avec un nouveau domaine.
Avant de toucher aux fichiers, je recommande toujours de gérer l’accès et de réduire le risque de propagation.
Concrètement, cela veut dire:
1) Sécuriser les comptes et l’accès. Révoquez les sessions si votre hébergement le permet, vérifiez les utilisateurs WordPress, et supprimez ceux que vous ne reconnaissez pas. Changez les mots de passe de tous les comptes administrateur et, si vous utilisez l’identification à deux facteurs, assurez-vous qu’elle est active et que vous n’avez pas perdu l’appareil.
2) Mettre WordPress et les plugins à jour. Oui, ça semble évident. Mais dans les incidents “tracking injecté”, l’infection s’accroche parfois à un plugin non maintenu ou à une version WordPress ancienne, et les correctifs peuvent fermer la porte.
3) Couper l’effet immédiat sur le front si nécessaire. Si vous observez des redirections ou un code très agressif, mettre le site en maintenance peut vous donner une fenêtre de travail. Si votre hébergement dispose d’un pare-feu applicatif ou d’une fonction de https://gardewp.fr/nettoyage-malware-wordpress/ filtrage, utilisez-la, mais ne comptez pas uniquement dessus.
Je préfère faire ce cadrage parce que j’ai déjà vu des équipes nettoyées “proprement” se retrouver avec une deuxième salve dans la nuit. Les injections se relancent si le point d’entrée reste présent.
Où chercher: les endroits typiques où l’injection se cache
Le bon endroit pour commencer est celui qui reflète le symptôme. Si le script injecté apparaît dans le ou avant , il y a de fortes chances qu’un mécanisme PHP alimente ce contenu. Les thèmes et plugins sont les coupables fréquents, mais pas les seuls.
Sur WordPress, les points d’attaque qui reviennent souvent pour des scripts de tracking injectés sont:
- functions.php d’un thème (parfois un thème enfant), des fichiers PHP ajoutés dans un thème ou un plugin, avec des noms “banals” ou des chemins atypiques, des fichiers qui ne servent à rien côté logique, mais qui contiennent du code obfusqué et une fonction d’injection, des modifications dans des templates, parfois avec un echo ou un print qui ajoute le script, des crochets enregistrés dans des hooks WordPress, par exemple via add_action('wp_head', ...).
Un détail important: la plupart des infections sérieuses ajoutent du code qui n’est pas juste “du JavaScript”. Souvent, il y a une étape PHP qui décide si l’injection doit être active pour cette requête. Cela peut dépendre de l’URL, de la présence d’un cookie, ou du type de page.
C’est là que l’inspection gagne face à la simple suppression du script côté navigateur. Supprimer l’output sans comprendre le mécanisme, c’est laisser la partie cachée en place.
Méthode de diagnostic rapide: comprendre ce qui est injecté et par quel chemin
Avant d’éditer, prenez des notes. Votre but est de relier un symptôme visible à un fichier responsable.
Une approche pratique consiste à:
- ouvrir la page infectée et comparer le HTML avec une version saine (si vous en avez une), regarder l’onglet réseau (dans les outils de développement) pour identifier les domaines ou chemins chargés par le script injecté, identifier une portion de code unique que vous pouvez rechercher dans vos fichiers (par exemple un identifiant, une chaîne encodée, un nom de fonction, un fragment de domaine).
Ensuite, faites une recherche dans l’installation WordPress:
- dans les fichiers PHP de wp-content/themes, dans wp-content/plugins, dans parfois la racine (selon ce que vous trouvez), et dans les fichiers d’extension ou d’include.
Si vous voyez du code obfusqué, cherchez des marqueurs plus stables que le JS lui-même, par exemple eval(, base64_decode(, str_rot13(, gzinflate(, preg_replace avec du code, ou l’usage d’une variable “cache” qui reconstruit du contenu.
Je le dis parce que c’est souvent le point qui fait perdre du temps: si vous cherchez seulement le nom du domaine injecté et qu’il est généré à partir d’un tableau ou d’un encodage, vous n’allez rien trouver. En revanche, base64_decode et eval apparaissent presque toujours dans la partie responsable.
Étapes concrètes pour supprimer l’injection et éliminer le point d’entrée
Une fois que vous avez localisé la zone à l’origine de l’injection, le travail devient plus mécanique. L’objectif est de supprimer le code malveillant, puis de restaurer la cohérence de WordPress.
Voici une séquence réaliste, à adapter selon votre niveau de confort technique:
Faire un inventaire immédiat: sauvegarde complète (fichiers + base de données) et capture du code “infecté” (source HTML et fragments de script). Identifier l’auteur exact de l’injection: cherchez le fragment unique trouvé dans le ou le parmi functions.php, templates du thème, et fichiers PHP des plugins actifs. Supprimer le code malveillant: modifiez le fichier incriminé ou remplacez-le par la version saine (si vous avez le thème/plugin via votre dépôt), puis vérifiez que l’injection disparaît. Retirer le mécanisme de réinfection: contrôlez les fichiers nouvellement créés, les tâches planifiées côté WordPress, et les utilisateurs ou plugins ajoutés. Désactivez les plugins inutiles et réexécutez un contrôle de cohérence. Restituer et valider: rétablissez les fichiers manquants ou modifiés, testez sur plusieurs pages, puis surveillez 24 à 48 heures si votre incident a tendance à revenir.Deux points de jugement ressortent souvent. D’abord, si vous ne trouvez pas le fichier exact responsable mais que vous êtes certain que l’injection existe, vous pouvez restaurer le thème et les plugins à partir de versions connues, mais sans ignorer la recherche de point d’entrée. Ensuite, si vous trouvez du code dans un plugin tiers que vous utilisez, la tentation est de “juste supprimer les lignes injectées” et laisser le reste. Si le plugin a été modifié de façon suspecte, je préfère le réinstaller proprement plutôt que de tenter d’enlever uniquement la partie visible.
Le piège des “réparations” incomplètes: le code est peut-être dans la base de données
Certains scripts de tracking injectés ne passent pas par un fichier PHP clair dans le thème ou le plugin. Le contenu peut être stocké dans la base de données, puis réinjecté lors du rendu. Cela arrive via des options, du contenu dans des champs personnalisés, ou des endroits inattendus qui affichent ensuite un morceau HTML.
C’est plus délicat, parce que vous ne “voyez” pas le code dans un fichier à côté de l’infection. Vous voyez un output dans le front, et tout le reste a l’air normal au niveau des fichiers.
Dans ce cas, les indices aident encore. Souvent, le script contient des identifiants, et vous pouvez rechercher un morceau de chaîne côté base de données. Dans phpMyAdmin ou via un outil d’administration, cherchez des occurrences de fragments unique (domaine, nom de fonction, identifiant de campagne) dans la base.
Trade-off important: vous pouvez effacer une option qui contient un script, mais si l’attaque a mis en place une routine qui réécrit cette option à chaque chargement, vous effacez et ça revient. C’est pour cela que la chasse doit couvrir aussi les points d’entrée fichier et les mécanismes de déclenchement.
Reconnaître le faux “tracking” et le vrai code d’infection
Il y a une différence nette entre un script de tracking “habituel” et un script injecté malveillant, même si les deux sont des balises
Un tracking légitime vient généralement d’un gestionnaire que vous avez activé, il est installé de façon stable (par exemple via un tag manager), et vous pouvez le relier à une configuration. Il ne dépend pas d’un encodage complexe, ni d’une reconstruction dynamique de code.
À l’inverse, un script injecté malveillant suit souvent un motif technique plus agressif:
- charge de script depuis un domaine inconnu, logique de condition sur les requêtes, obfuscation PHP pour fabriquer du contenu, génération dynamique d’URL ou de paramètres, présence de fonctions d’exécution de code en PHP.
Si vous observez eval en PHP, ou une chaîne encodée reconstruite en mémoire, vous êtes dans un cas d’infection probable, même si le script final ressemble à du tracking.
Quand vous devez remplacer plutôt que réparer
Sur un chantier, je préfère expliquer une règle simple: si vous trouvez un fichier PHP modifié et qu’il y a un doute sur l’intégrité, le remplacement propre vaut souvent mieux que la réparation manuelle.
Remplacer, cela veut dire:
- réinstaller le plugin depuis la source officielle que vous utilisez, ou restaurer votre version via dépôt, réimporter un thème sain, remettre les fichiers WordPress de base en place si vous voyez des modifications non attendues, puis uniquement après, réactiver progressivement les composants.
Cette approche réduit le risque de laisser un morceau de “charge utile” dans un coin du fichier.
Le trade-off est le temps. Réinstaller une grosse base de plugins peut casser des réglages, et restaurer un thème peut demander de vérifier les customisations. Mais dans un incident de tracking injecté, la stabilité après nettoyage est plus précieuse que de gagner une heure en bricolage.
Vérifications après nettoyage: ce que je teste, et ce que je surveille
Le nettoyage ne se termine pas au moment où “le script n’est plus visible dans le HTML”. Je teste aussi la stabilité de l’injection sur plusieurs pages, parce que certaines infections n’agissent que sur des routes spécifiques.
Après avoir supprimé le code, j’effectue généralement:
- une vérification du HTML sur la page d’accueil et sur une page interne (souvent celle où le tracking apparaissait), un contrôle du réseau dans les outils développeur pour confirmer que les domaines suspects ne se chargent plus, un passage sur des pages qui déclenchent parfois l’injection, comme les formulaires, les pages d’archives, ou les pages avec des blocs dynamiques, un contrôle de l’apparition de scripts dans les versions “non connectées” et “connectées”.
Ensuite je surveille, sur 24 à 48 heures. Pas parce que je pense que tout revient immédiatement, mais parce que certaines injections sont temporisées ou conditionnées à des sessions spécifiques.
Si votre site est très consulté, vous pouvez aussi regarder des indices non techniques, comme la perte de confiance sur certaines pages, des métriques d’anomalies si vous avez un monitoring, ou des signaux d’alertes côté navigateur. Je ne base pas la décision uniquement sur ça, mais en complément.
Prévenir: durcir WordPress sans le rendre ingérable
Après un incident, la tentation est de “tout verrouiller” sans stratégie. Le mieux est d’agir sur trois axes: réduire la surface d’entrée, réduire la capacité d’écriture non contrôlée, et améliorer la détection.
Sur l’axe surface d’entrée, une hygiène simple mais constante compte énormément: garder WordPress et les plugins à jour, limiter les plugins à ceux qui sont vraiment nécessaires, supprimer ceux qui ne servent plus, et désactiver les éditeurs internes si votre organisation n’en a pas besoin. Beaucoup d’infections utilisent des chemins d’édition ou d’accès déjà disponibles.
Sur l’axe écriture non contrôlée, le contrôle des permissions serveur et l’usage d’un compte dédié pour l’administration peuvent éviter certains scénarios. Sur certains hébergements, je vois des fichiers se régénérer avec des permissions incohérentes, et ça facilite la persistance.
Enfin, sur la détection, avoir des alertes sur les modifications de fichiers, ou au minimum une vérification régulière des différences entre votre dépôt et votre production, change tout. Quand une injection réapparaît, vous devez la traiter vite, avant que les auteurs aient le temps d’ajouter des variantes.
Cas particuliers: thèmes enfants, builder et intégrations
Un point qui revient dans les chantiers, c’est la différence entre une modification “normale” et une injection.
Avec un thème enfant, il est courant que functions.php soit modifié. Avec un builder de pages, des scripts peuvent être ajoutés via des paramètres. Avec des intégrations marketing, des scripts tiers apparaissent parfois dans les pages.
Donc, si vous cherchez à supprimer “toute balise script nouvelle”, vous risquez d’effacer votre propre tracking légitime ou de casser une fonctionnalité.
La bonne approche consiste à relier chaque script à une provenance. Si le script injecté malveillant est obfusqué, ou qu’il charge des domaines non attendus, vous n’avez pas besoin d’hésiter. Si c’est un script propre, mais que vous n’étiez pas sûr de son origine, vous devez vérifier la source de configuration plutôt que supprimer aveuglément.
C’est aussi pour ça que je conseille de sauvegarder et de documenter. Sans référence, on confond vite “changement” et “infection”.
Conclusion de terrain: nettoyer, puis vérifier, puis durcir
Supprimer des scripts de tracking injectés sur WordPress, ce n’est pas uniquement un exercice technique. C’est un enchaînement de décisions, selon ce que vous trouvez: réparer ou remplacer, chercher dans les fichiers ou dans la base, couper les effets tout en gardant votre fenêtre de diagnostic.
Si vous ne deviez retenir qu’une ligne de conduite, ce serait la suivante: ne vous contentez pas de retirer l’output visible. Cherchez le mécanisme qui produit l’output, éliminez la porte d’entrée, puis confirmez que l’injection ne revient pas.
Si vous voulez, dites-moi ce que vous observez exactement, par exemple où le script apparaît (dans le ou juste avant ), un fragment du code visible (en masquant les identifiants si nécessaire), et si vous avez des plugins spécifiques pour le marketing ou l’analytics. Je pourrai vous orienter sur les recherches les plus rentables dans votre cas précis, sans vous pousser à tout réinstaller à l’aveugle.
