WP Manifestindependent plugin directory
manifest / security / hidden-link-guard

Hidden Link Guard

Plugin WordPress : détecte et nettoie les liens masqués injectés en base de données (spam SEO), avec alerte au tableau de bord et nettoyage réversible.

by Wadie Aroua · github.com/waddou/hidden-link-guard · website

0stars
1release downloads
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/waddou/hidden-link-guard/releases/download/v1.0.3/hidden-link-guard.zip

Readme

Hidden Link Guard

Plugin WordPress qui détecte et nettoie les injections de spam SEO en base de données : les blocs HTML rendus invisibles au visiteur mais lus par les moteurs de recherche, insérés dans le contenu des articles.

Développé par Wadie Arouanoticiel.com

<div style="position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;overflow:hidden">
  <p><a href="https://domaine-spam.tn/">domaine-spam</a></p>
</div>

<div style="display: none;">
  <ul><li><a href="https://autre-spam.com" rel="dofollow">autre-spam</a></li></ul>
</div>

Installation

  1. Copier le dossier hidden-link-guard/ dans wp-content/plugins/.
  2. Activer « Hidden Link Guard » dans Extensions.
  3. Ouvrir Link Guard dans le menu d'administration et cliquer sur Lancer un scan.

Ce que fait le plugin

  • Alerte en haut de toutes les pages de wp-admin dès qu'une injection est en attente de traitement, plus un widget sur le tableau de bord.
  • Scan de l'ensemble de la base, par lots, avec barre de progression.
  • Nettoyage en un clic, global ou ligne par ligne.
  • Restauration de n'importe quelle valeur nettoyée : chaque original est sauvegardé avant modification.
  • Scan planifié chaque nuit et alerte e-mail en cas de détection.
  • Export CSV du rapport.

Ce qui est nettoyé exactement

Seule la portion injectée est retirée. Jamais l'article, jamais le champ.

Le plugin localise la balise ouvrante du bloc masqué, compte la profondeur d'imbrication pour trouver sa fermeture exacte, et supprime uniquement cet intervalle. Le reste du champ est réécrit à l'identique, octet pour octet — les tests le vérifient en contrôlant que le résultat est une sous-chaîne exacte de la valeur d'origine.

L'écriture se fait directement en base plutôt que par wp_update_post, dont les filtres (kses, wpautop) reformateraient des parties saines du contenu.

Comment la détection fonctionne

Une liste de domaines spam serait obsolète au scan suivant. Le plugin repère la signature structurelle de l'injection. Un bloc n'est signalé que si :

  1. son style inline le rend invisible — display:none, visibility:hidden, opacity:0, font-size:0, positionnement hors écran (left:-9999px), text-indent très négatif, dimensions 1px/0 avec overflow:hidden, clip ou clip-path ; et
  2. il contient au moins un lien vers un domaine externe au site.

La seconde condition est le garde-fou principal : un bloc caché sans lien sortant n'est jamais signalé. Les conteneurs d'accessibilité légitimes (screen-reader-text, sr-only, visually-hidden, skip-link…) sont exclus d'office — WordPress core en utilise.

Chaque bloc reçoit un score ; le signalement démarre à 50. rel="dofollow" (attribut non standard, propre aux outils de spam) et le positionnement hors écran pèsent le plus lourd. Le score est affiché pour vous laisser arbitrer les cas limites.

Emplacements analysés

Table Champs
posts post_content, post_excerpt, post_title (hors révisions et médias)
postmeta meta_value
options option_value (hors transients)
comments comment_content
usermeta meta_value
term_taxonomy description

Les valeurs sérialisées sont désérialisées, nettoyées récursivement, puis re-sérialisées : un simple remplacement de texte corromprait les longueurs encodées dans la structure.

Tests

Les deux suites s'exécutent en PHP pur, sans installation WordPress :

php tests/test-detector.php     # détection, préservation du contenu, faux positifs
php tests/test-serialized.php   # intégrité des valeurs sérialisées

Ou les deux d'un coup :

bash tests/run-all.sh

La suite de détection tourne sur un article réellement contaminé (tests/fixtures/injected-post.html) et vérifie notamment que les 9 blocs injectés partent, que l'article reste intact, et que huit scénarios de faux positifs ne déclenchent aucun signalement.

Personnalisation

Le filtre hlg_own_hosts permet d'ajouter des domaines considérés comme internes — utile si votre site publie légitimement des liens vers vos autres domaines et que ceux-ci apparaissent dans des blocs masqués :

add_filter( 'hlg_own_hosts', function ( $hosts ) {
    $hosts[] = 'mon-autre-domaine.fr';
    return $hosts;
} );

Avant de nettoyer en masse

Le plugin sauvegarde chaque valeur d'origine et permet de la restaurer, mais une sauvegarde complète de la base avant une première campagne de nettoyage reste la bonne pratique.

Traiter la cause, pas seulement le symptôme

Nettoyer la base ne referme pas la porte d'entrée. Si les injections réapparaissent après un scan propre, le vecteur est toujours actif : extension ou thème vulnérable, compte administrateur compromis, fichier PHP porte dérobée, identifiants FTP ou SQL dérobés.

Sur un hébergement OVH

La procédure détaillée figure dans readme.txt, section « Traiter la cause sur un hébergement OVH ». En résumé :

  1. Réinitialiser tous les identifiants depuis l'espace client OVH : FTP/SFTP (en supprimant les utilisateurs additionnels non créés par vous), base de données, compte OVH avec double authentification. Côté WordPress, changer les mots de passe administrateurs et regénérer les clés de sécurité de wp-config.php — cela déconnecte toutes les sessions actives, y compris celle d'un intrus.
  2. Activer le pare-feu applicatif sur mutualisé, via un fichier .ovhconfig à la racine contenant http.firewall=security. Ce fichier fixe aussi la version PHP : une version en fin de vie est un vecteur d'entrée courant.
  3. Dater l'intrusion via les logs de l'hébergement, consultables depuis l'espace client. Chercher les POST vers des fichiers PHP inhabituels (notamment dans wp-content/uploads/), les accès à xmlrpc.php, les rafales sur wp-login.php.
  4. Restaurer une sauvegarde OVH antérieure à cette date. Restaurer la base seule ne supprime pas une porte dérobée dans les fichiers, et l'inverse est tout aussi vrai.
  5. Chercher les portes dérobées : réinstaller le cœur WordPress depuis l'administration, repérer les fichiers PHP dans les dossiers d'upload et de cache, inspecter wp-config.php et les .htaccess. Bloquer l'exécution de PHP dans wp-content/uploads/.
  6. Vérifier les tâches CRON de l'hébergement : une tâche inconnue peut réinjecter le spam après chaque nettoyage.

Le scan planifié quotidien sert précisément à détecter une réapparition, signe que le vecteur est encore ouvert.

Changelog

Voir CHANGELOG.md.

Licence

GPL-2.0-or-later. Voir LICENSE.

Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v1.0.3 Jul 27, 2026 hidden-link-guard.zip 1