WordPress infecté : nettoyer les injections JavaScript et iframe invisibles

Un site WordPress infecté ne se trahit pas toujours par des signaux spectaculaires. Parfois, tout semble normal, pages blanches ou erreurs 404 absentes, trafic encore là, formulaire qui envoie toujours. Et pourtant, dans le code source, dans les scripts chargés, ou dans la manière dont certaines pages se comportent selon l’utilisateur, on voit apparaître des injections JavaScript et des iframes invisibles. Ce sont souvent les formes les plus difficiles à repérer, parce qu’elles se cachent dans l’ombre: minification, concaténations, chargement différé, conditionnement sur l’agent navigateur, ou insertion dans des fichiers que personne ne touche d’habitude.

Le nettoyage, lui, demande une méthode. Pas une chasse aux “petits indices” au hasard, mais une approche qui empêche de casser le site, limite la perte de contenu, et surtout empêche la réinfection pendant que vous nettoyez.

Les symptômes qui ne crient pas “piratage”, mais qui posent question

Quand j’ai dû intervenir sur un WordPress “infecté” qui avait l’air sain, le premier signal n’était pas un blocage de navigateur ni une alerte de sécurité. C’était un comportement subtil: sur certaines pages, le téléchargement d’un fichier déclenchait parfois une redirection minute vers une URL sans rapport. Rien dans l’interface. Rien dans les plugins installés. Dans le code rendu, par contre, on voyait des balises et des scripts injectés.

Voici ce que j’ai l’habitude de surveiller, parce que ça oriente vers des injections JavaScript et des iframes invisibles:

    Des changements dans le HTML d’une page seulement sur certaines conditions (pays, navigateur, langue, referrer). Une dégradation légère du temps de chargement, parfois masquée par un cache qui retarde l’apparition du problème. Des scripts qui n’ont aucune raison d’exister, avec des noms variables, parfois hexadécimaux ou courts, qui s’exécutent “au moment où il faut”. Des iframes de 1 pixel, sans attributs explicites côté front, ou avec des styles qui les rendent invisibles (display none, opacity 0, position absolue hors écran). Des tentatives de chargement vers des domaines nouvellement créés ou “trop” spécifiques, souvent via des endpoints longs et opaques.

Les attaques les plus pénibles ne cherchent pas toujours à “défacer” votre page. Elles se contentent d’ajouter une couche: un iframe invisible qui alimente une page de redirection, ou une fonction JavaScript qui déclenche un script additionnel depuis une source externe. Votre site continue de servir son contenu, ce qui rend la détection plus lente.

Pourquoi les injections ciblent WordPress (et où elles se cachent)

WordPress offre plusieurs surfaces d’attaque: base de données, fichiers de thème, plugins, et surtout les mécanismes d’insertion de contenu. Les injecteurs adorent l’endroit où vous avez l’habitude de modifier du code sans le voir tous les jours.

Dans la pratique, les points d’infection fréquents se répartissent souvent en trois familles.

1) Modifications dans les thèmes et fichiers “utilitaires”

Les thèmes sont un terrain classique, parce qu’ils contrôlent la génération HTML. Une injection dans un fichier comme header.php, un composant partiel, ou un fichier “helper” utilisé par le thème peut toucher un grand nombre de pages. Il suffit d’une condition mal comprise pour que le code se déclenche parfois seulement.

J’ai déjà vu des injections ajoutées juste avant un appel à un script normal, de manière à ce que la présence passe inaperçue. Parfois le code est encapsulé dans des structures illisibles, parfois dans des fonctions “tampon” qui rendent le tout plus compliqué à analyser.

2) La base de données et les options “auto” (thèmes, widgets, contenus)

Les iframes invisibles et les scripts peuvent être stockés dans des champs que WordPress rend ensuite dans la page. Une option de thème, un champ widget, une ressource injectée via un shortcode, ou un champ “custom code” s’il existe, peuvent servir de canal.

Le piège, c’est que le code peut être valide, syntaxiquement propre, mais injecté à mauvais endroit ou avec une logique d’exécution cachée. Dans certains cas, la base contient un fragment de script qui ressemble à une simple variable, mais qui finit par appeler une fonction malveillante.

3) Les fichiers de plugins ou des “webshells” déguisés

Beaucoup de gens pensent en premier aux fichiers PHP, mais c’est parfois plus discret: un plugin modifié, un fichier supplémentaire dans un dossier de plugin, ou un fichier “vendor” qui n’avait aucune raison d’être là. Et parfois, il y a une double couche: un script JavaScript injecté qui charge ensuite un fichier distant, et ce fichier distant sert à piloter des comportements variables.

Ce que sont exactement les iframes invisibles (et comment elles piègent les diagnostics)

Quand on dit “iframe invisible”, on ne parle pas d’une seule technique. Souvent, l’iframe est rendue invisible par des styles, mais elle reste active côté navigateur. Les méthodes classiques incluent:

    iframe de taille 1x1 pixel style="display:none" ou style="opacity:0" iframe positionnée hors écran attributs qui minimisent l’impact visuel, tout en laissant le chargement se faire

Le but n’est pas toujours de “montrer” quelque chose. Parfois l’iframe sert de relais pour exécuter un script dans un contexte séparé. Parfois elle rend possible un comportement de redirection, ou elle collecte des signaux (cookies, identifiants de session, paramètres de tracking) avant de déclencher une action.

Un point important: même si l’iframe est invisible, elle peut causer des signaux réseau repérables. Ouvrir les DevTools, regarder l’onglet réseau et comparer ce que fait le navigateur sur une page “propre” versus une page “affectée” est très souvent révélateur.

La stratégie de nettoyage qui marche vraiment (sans casser le site)

Avant de toucher au code, j’insiste sur un principe: le nettoyage doit être “séquentiel” et “verrouillé”. Si vous supprimez un morceau visible mais laissez un point de persistance, le malware revient.

Voici comment je structure mentalement une intervention sérieuse:

Isoler le problème: quelle zone est concernée (toutes les pages, seulement certaines, seulement la page d’accueil, seulement les visiteurs non connectés). Repérer le point d’entrée: dans quel fichier ou champ est le code injecté. C’est souvent le moment le plus long. Créer une base de comparaison: versions de fichiers avant modification, ou copie fiable, sinon au minimum des hashes, et un export SQL avant modifications si possible. Nettoyer avec prudence: restaurer des fichiers depuis une source saine, remplacer les thèmes et plugins par des versions propres quand c’est raisonnable. Éliminer la persistance: comptes, tokens, fichiers ajoutés, cron, options de base, et règles d’accès. Vérifier: recharger le site depuis un navigateur différent, vider caches, tester des pages spécifiques. Renforcer: durcir l’accès, retirer les “angles morts”, changer les identifiants exposés.

Le trade-off classique, c’est le coût de restauration. Remplacer “tout” (thème, plugins) est efficace mais peut casser des réglages personnalisés, et certains plugins ont des dépendances. Inversement, modifier uniquement le fichier suspect peut échouer si la persistance est ailleurs.

Dans les infections avec iframe et JavaScript invisibles, je privilégie généralement une approche hybride: restauration ciblée des fichiers du thème et des plugins les plus probables, inspection approfondie des zones de sortie HTML, puis nettoyage de la base et des accès.

Mettre le site à l’abri pendant l’analyse

Pendant que vous cherchez, le malware peut continuer à se propager. Même sans “propagation”, il peut provoquer des accès externes qui compliquent le diagnostic.

L’approche la plus pragmatique consiste à mettre temporairement le site en mode maintenance, ou au minimum à limiter l’accès pendant la collecte. Si vous devez garder l’accessibilité, assurez-vous de tester depuis un environnement contrôlé.

Concrètement, dans un cas réel, j’ai déjà perdu du temps parce que le cache du serveur affichait une version déjà contaminée alors que les fichiers venaient d’être modifiés. Résultat, j’analysais “le mauvais univers”. Tant que le cache n’est pas clarifié, le site ment.

Repérer l’injection dans le code rendu: HTML, scripts, et conditions

La première question à se poser est simple: le JavaScript injecté est-il présent dans le HTML initial, ou ajouté après coup via un script “loader” ?

Quand vous inspectez une page affectée, vous cherchez:

    des balises ajoutées hors des scripts attendus des sections HTML soudaines où aucun composant du thème ne devrait générer ce code un iframe injecté qui n’a aucune raison d’être là des attributs inhabituels sur body, head, ou autour du footer des scripts qui chargent des URL externes qui ne sont pas celles de vos comptes marketing, ou de vos outils habituels

Souvent, la meilleure méthode est la comparaison. Ouvrez deux sessions: une avec compte administrateur, une autre en navigation privée. Les infections conditionnent fréquemment sur la présence de cookies de session ou sur l’agent navigateur. Si l’injection n’apparaît pas pour l’admin, ça oriente vers un déclenchement ciblé.

Ensuite, remontez l’injection vers la source. Si le script est présent dans le HTML rendu, il provient presque toujours d’un fichier PHP, d’un hook WordPress, d’une option enregistrée en base, ou d’un contenu réinjecté via un builder.

Traquer le point de persistance, pas seulement la charge visible

La charge visible est souvent un “payload” qui fait le job. Le point de persistance, lui, est ce qui fait revenir le malware après suppression.

Dans un WordPress infecté, les persistance les plus courantes que je rencontre, dans l’ordre d’attaque possible, sont:

image

    un compte admin compromis un fichier PHP modifié (thème, plugin) une option de base de données (head injection, footer injection, custom fields) un cron malveillant ou une tâche automatisée un fichier supplémentaire qui charge un code au démarrage un plugin “de façade” qui se fait passer pour un outil légitime

Le nettoyage “propre” consiste à identifier où l’injection est générée. Supprimer le code injecté dans le HTML peut suffire temporairement, mais si l’injecteur modifie la génération ensuite, il reviendra.

Méthode de nettoyage pas à pas (avec prudence sur les sauvegardes)

Je vais proposer une procédure pratique, mais elle reste volontairement prudente, parce qu’un mauvais geste sur un thème ou un plugin peut casser votre site au-delà de l’infection.

Voici mon déroulé type quand il y a à la fois JavaScript injecté et iframe invisibles, et que je suspecte une compromission.

Checklist de travail

    Sauvegarder les fichiers WordPress et exporter la base (au minimum les tables liées aux options et aux contenus). Mettre en maintenance ou réduire l’accès pendant la phase d’analyse, pour éviter de masquer des différences dues au cache. Comparer HTML et réseau entre navigation privée et session admin, afin de localiser la condition de déclenchement. Identifier le code source de l’injection (fichiers de thème, plugins, hooks, options stockées dans la base). Remplacer les thèmes et plugins suspects par des versions propres, puis vérifier à nouveau après purge des caches.

Cette checklist ne remplace pas l’analyse, elle la cadre.

Nettoyer les injections JavaScript: ce que je regarde avant de supprimer

Quand vous trouvez un script injecté, la tentation est de le supprimer directement. Ça peut marcher, mais je préfère d’abord comprendre comment il a été intégré.

Les injections JavaScript prennent souvent une forme qui facilite l’obfuscation. Parfois c’est un simple appel à une URL externe, parfois c’est une fonction qui construit du code au runtime. Ce type d’écriture est rarement “accidentel”. Si le script est dans un fichier de thème, je vérifie d’abord si le fichier a été modifié hors processus normal (date de modification, taille anormale, différences difficiles à expliquer).

Le bon geste, en pratique, c’est:

    vérifier si le même code existe ailleurs (options, footer, contenu de widget) vérifier si les mêmes patterns existent sur plusieurs fichiers rechercher le fragment clé dans l’ensemble du projet (mots rares, URL externes, identifiants de domaine, marqueurs de l’attaquant)

Une fois repéré, je supprime à la source, pas seulement à l’affichage. Et je remplace les fichiers modifiés par une version propre si possible.

Traiter les iframes invisibles sans casser le rendu

Les iframes invisibles sont souvent chargés dans le footer ou dans des zones globales. Dans ces cas, enlever l’iframe peut régler le souci, mais si l’iframe est insérée à cause d’un composant légitime (rare, mais possible), vous risquez de casser un tracking ou une fonctionnalité tierce.

C’est pour ça que je m’appuie sur une logique de “raison d’être”. Si votre site n’utilise pas d’intégration dont l’iframe est la forme normale (certains services l’utilisent), une iframe ajoutée nulle part est presque toujours un https://gardewp.fr/ signal rouge.

Ce que je fais généralement:

    vérifier dans la page où l’iframe apparaît, à quel endroit du DOM inspecter les attributs et le contenu de l’URL de src tester la page après suppression, en surveillant le réseau comparer avec un site miroir (si vous avez une version non contaminée) ou au moins avec une autre page censée être identique

Vérifier l’intégrité des thèmes et plugins (la partie la plus “fastidieuse”)

Quand vous avez des injections dans WordPress, l’un des meilleurs accélérateurs est de se donner une règle: “tout ce qui est modifié hors du processus normal doit être remplacé”.

Cela veut dire que, même si vous trouvez le code malveillant dans un seul fichier, vous remplacez le thème ou le plugin concerné par une version propre. Pourquoi? Parce que l’attaquant peut avoir modifié plus que ce que vous voyez immédiatement. Parfois la charge d’hier est retirée, mais le point de persistance reste actif sous une autre forme.

Le compromis, c’est la configuration personnalisée. Heureusement, WordPress sépare souvent la configuration de l’option, du code des fichiers. Quand vous remplacez un plugin, vous perdez rarement vos contenus et paramètres, sauf si le plugin utilise un stockage dans ses fichiers ou si vous effacez trop large.

Dans un incident récent, j’ai remplacé un plugin “cache” censé être inoffensif. Après remplacement, le site redevenait stable, mais la page restait “légèrement bizarre” sur mobile. En remontant, on a trouvé une modification dans le thème. Le nettoyage initial avait corrigé le symptôme, pas la cause globale. D’où l’importance de vérifier au-delà du script principal.

Sécuriser l’accès: admins, mots de passe, sessions, et tokens

Un WordPress infecté n’est pas seulement un problème de code. Il est souvent le symptôme d’un accès compromis. Même si vous nettoyez parfaitement JavaScript et iframe, si un attaquant garde un accès, il remettra la charge.

Je procède alors par étapes, de façon pragmatique:

    forcer la rotation des mots de passe des comptes admins et des comptes utilisés pour le FTP ou l’accès serveur si c’est votre cas révoquer les sessions actives (selon votre configuration et votre hébergeur) vérifier les utilisateurs ajoutés récemment, avec rôles élevés supprimer les clés d’API ou plugins externes installés “à la volée” si vous les retrouvez inspecter les tâches planifiées (cron) si vous suspectez une persistance automatisée

Selon votre hébergeur et votre stack, l’interface et les termes peuvent varier, mais l’idée reste identique: vous coupez la porte que l’attaquant utilise pour revenir.

Comment savoir si vous avez vraiment fini: tests concrets

Un contrôle “visuel” est insuffisant, parce que les injections peuvent être conditionnelles. Le malware adore ce détail. Parfois il ne s’affiche que pour une partie des visiteurs, ou seulement quand certains scripts tiers répondent.

Je fais donc des vérifications qui couvrent à la fois rendu et exécution:

    charger plusieurs pages types (accueil, page produit, page contact, une page qui a un shortcode si vous en utilisez) tester en navigation privée et avec un compte admin vider caches applicatifs et caches CDN si vous en avez contrôler le réseau dans les DevTools, en cherchant de nouveaux domaines ou des requêtes inattendues rechercher à nouveau, dans le code source du site, les fragments uniques de l’injection (URLs, variables obfusquées, marqueurs)

Le signe que le nettoyage est “bon” est souvent la disparition des requêtes réseau suspectes, et l’absence des scripts dans la source HTML rendue.

Deux pièges qui coûtent cher en temps

Piège 1: corriger un fichier copié mais garder l’ancienne version ailleurs

WordPress a ses doubles lieux de rendu. Un fichier peut être inclus via un autre chemin, ou il peut exister plusieurs thèmes (un thème parent et un enfant). Dans un cas, l’injection était dans un thème enfant, mais un cache continuait de servir le thème parent modifié précédemment. Résultat, on pensait avoir corrigé, mais l’ancien code persistait dans l’exécution.

La solution est simple en théorie, mais exigeante en pratique: identifier tous les thèmes actifs, enfants, templates et hooks utilisés, puis vérifier la totalité.

Piège 2: la base de données contient encore le morceau d’injection, même après remplacement de fichiers

Certains builders et champs personnalisés peuvent réinjecter du contenu. Si vous supprimez le code côté PHP, mais que la base continue de contenir un champ “custom code” ou un contenu de type texte, le problème peut réapparaître.

C’est pour ça qu’un export SQL et une recherche par fragments dans les tables utiles sont très utiles. Vous n’avez pas besoin de “tout” lire, vous cherchez juste les marqueurs.

Prévenir la réinfection: mesures réalistes, pas des promesses

Après nettoyage, le but n’est pas d’empiler une tonne de sécurité, mais de réduire les angles morts qui ont permis l’infection.

Je recommande surtout de reprendre votre hygiène d’accès et votre discipline de mise à jour. Les infections qui insèrent du JavaScript via des points de sortie PHP viennent souvent d’une compromission qui s’est installée sur une faille de plugin, un mot de passe faible, ou une mise à jour négligée.

Une logique simple s’applique:

    maintenir WordPress, thèmes et plugins à jour supprimer les thèmes et plugins inutilisés limiter les rôles et vérifier les nouveaux utilisateurs surveiller les changements de fichiers (au moins sur le thème et les plugins actifs) durcir l’accès FTP, SSH, et l’interface d’administration utiliser une stratégie de sauvegarde vérifiée, avec restauration testée au moins une fois

Le mot “nettoyer site WordPress infecté” revient souvent dans les recherches, mais la réussite durable vient presque toujours de la prévention. Sans ça, vous recommencez dans quelques semaines.

Quand appeler un professionnel (et comment éviter le mauvais choix)

Il y a des situations où le nettoyage dépasse le simple “supprimer le script”. Si l’infection a des traces de persistance multiples, si vous suspectez une compromission serveur, ou si la base et plusieurs fichiers sont touchés, il vaut mieux se faire aider.

Je ne dis pas cela pour “faire peur”, je le dis parce que le coût d’une erreur peut être élevé: perte de contenus, restauration partielle, ou continuité de l’accès malveillant.

Avant de déléguer, demandez des éléments concrets: rapport de ce qui a été trouvé, liste des fichiers modifiés, méthodes de vérification, et comment ils valident l’absence de persistance. Un bon intervenant ne se contente pas d’un “ça a l’air propre”, il montre comment il l’a vérifié.

Un exemple de scénario réel (pour comprendre le déroulé)

Sur un site vitrine, le code source de la page d’accueil contenait un iframe qui ne faisait rien en apparence. Dans le réseau, on voyait des requêtes sortantes vers un domaine non lié à l’activité du site. En inspectant plus loin, on a constaté que le iframe n’était pas un ajout manuel visible dans l’interface, mais qu’il venait d’un fichier du thème: un bout de code ajouté dans un template chargé sur toutes les pages.

La suppression du iframe a immédiatement fait disparaître les requêtes sortantes pour une minute, puis elles sont revenues. Le motif était simple: un autre endroit réinjectait le payload, via une option enregistrée dans la base. Une fois la charge supprimée à la source base et fichiers, et après rotation des accès, le site est resté stable.

Ce scénario illustre deux points clés: il faut chercher la persistance, et il faut confirmer après purge des caches et test depuis une autre session. Sinon, vous corrigez le symptôme, pas la cause.

Points de contrôle finaux à faire avant de rouvrir au public

Avant de considérer le site “libéré”, je passe par une vérification de base, mais sérieuse:

    le site affiche comme attendu sur les pages principales les scripts et iframes suspects ont disparu dans le code source aucun domaine externe inattendu n’apparaît dans le réseau les comptes administrateurs et rôles sont propres, sans nouveaux ajouts le thème et les plugins actifs correspondent à une version saine les caches sont purgés, et la validation est faite en navigation privée

À ce stade, on peut rouvrir l’accès complet si vous aviez mis en maintenance, et surveiller pendant 24 à 72 heures. Certaines infections ont des déclenchements retardés, ou des conditions liées à la géolocalisation. La surveillance courte évite de rater une persistance cachée.

Dernier conseil: prenez des notes et gardez des preuves

Un incident de sécurité se gère mieux quand vous avez un dossier de travail. Prenez des captures de ce que vous voyez, notez les URLs externes, conservez une liste des fichiers modifiés, et gardez l’export de la base si vous l’avez.

Ce n’est pas seulement utile pour “raconter”. Si le problème revient, vous gagnez un temps considérable en sachant exactement ce que vous aviez trouvé au départ. Et si vous devez faire intervenir quelqu’un, vous lui donnez des repères concrets, pas un flou.

Nettoyer les injections JavaScript et les iframes invisibles sur WordPress, c’est à la fois technique et méthodique. Quand on traite la persistance, qu’on vérifie côté rendu et côté accès, et qu’on confirme après purge et tests réels, le risque de réinfection baisse fortement. Et surtout, vous rendez à votre site une stabilité qu’on ne peut pas “récupérer” avec un simple coup de suppression.