Comment fonctionne cette vérification
Scanaris analyse le HTML de ta page principale et parcourt tous les éléments ayant un attribut src, href ou action : scripts, images, feuilles de style, liens, formulaires. Pour chaque valeur, il vérifie si elle pointe vers un hôte qui ne devrait pas exister hors de ta machine ou de ton réseau : localhost, 127.0.0.1, 0.0.0.0, les IP privées 10.x.x.x, 192.168.x.x et 172.16.x.x à 172.31.x.x, et tout domaine se terminant par .local. S'il en trouve, il ouvre un constat de sévérité faible avec les premières références. Seul le HTML initial est examiné ; ce que le JavaScript construit ensuite n'est pas vu par cette voie.
Pourquoi c'est important
Une référence à http://localhost:3000/api/... en production a deux conséquences. La première est fonctionnelle : pour ton utilisateur, localhost est son propre ordinateur, donc cette image ne charge pas, ce formulaire part nulle part et ce script échoue en silence. La seconde est informationnelle : tu dis à n'importe qui que ton API tourne sur le port 3000, que ton backend interne s'appelle api.entreprise.local ou que ton réseau utilise la plage 10.0.1.x. Rien de tout ça n'est une faille exploitable en soi, d'où la sévérité faible, mais ce sont des pièces qu'un attaquant garde pour plus tard, et elles trahissent un déploiement sorti sans relecture.
D'où ça vient
C'est presque toujours une URL tapée à la main pendant le développement et jamais changée. L'IA qui a généré le projet a mis http://localhost:8000 dans le fetch du formulaire, ou dans le src d'une image de test, et ça marchait en local, donc c'est resté. Autres causes : un .env de développement qui a fini dans le build de production, un WordPress migré depuis un environnement local sans mise à jour de l'URL du site, ou un action de formulaire copié d'un exemple.
Comment corriger
- Sors les URL du code. La base de ton API va dans une variable d'environnement (
NUXT_PUBLIC_API_BASE,NEXT_PUBLIC_API_URL,VITE_API_URL) avec une valeur différente par environnement. En production, la plateforme (Vercel, Netlify, Railway) l'injecte au build. - Utilise des chemins relatifs dès que la ressource vit sur ton propre domaine :
/api/contactau lieu dehttp://localhost:3000/api/contact. Ils fonctionnent pareil en local et en production. - WordPress : mets à jour les URL du site dans les Réglages généraux et remplace les anciennes URL en base avec un outil qui respecte la sérialisation.
- Cherche dans le build avant de déployer. Une étape de CI qui échoue si la sortie compilée contient ces hôtes coupe le problème à la racine :
grep -rEl "localhost|127\.0\.0\.1|192\.168\.|\.local\b" dist/ .output/public/ 2>/dev/null
Si un fichier ressort, il y a une référence à corriger avant de publier.
Vérifie que c'est corrigé
curl -s https://tondomaine.com | grep -oE '(src|href|action)="https?://[^"]+"' | grep -iE "localhost|127\.0\.0\.1|0\.0\.0\.0|10\.[0-9]+\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.|\.local\b"
Rien ne doit sortir. Essaie aussi une ou deux pages intérieures, surtout celles qui ont des formulaires.
Questions fréquentes
C'est une image de test que personne ne voit. Est-ce important ?
Le navigateur de chaque visiteur essaie de la charger depuis son propre ordinateur, et le HTML continue d'annoncer ton hôte interne. Change-la ou supprime-la ; c'est l'affaire d'une minute.
Le JavaScript compilé est-il aussi examiné ?
Pas par cette vérification, seulement le HTML. Mais une URL interne dans le bundle s'accompagne souvent d'autres choses qui ne devraient pas y être ; secrets dans le JavaScript cherche clés et jetons, et commentaires HTML cherche les restes dans le HTML lui-même. Les trois ensemble couvrent ce qui reste habituellement d'un environnement de développement.
Mon lien pointe vers un domaine .local volontairement.
Les domaines .local sont réservés aux réseaux locaux (mDNS) et ne se résolvent pas sur internet. Si tu veux lier un outil interne, utilise un vrai sous-domaine avec authentification. Ce que ton appli laisse fuir sans le vouloir, avec plus d'exemples, est dans les secrets que ton appli laisse fuir dans le navigateur.