Wie diese Prüfung funktioniert
Scanaris analysiert das HTML deiner Startseite und geht alle Elemente mit einem src-, href- oder action-Attribut durch: Skripte, Bilder, Stylesheets, Links, Formulare. Für jeden Wert prüft er, ob er auf einen Host zeigt, der außerhalb deines Rechners oder Netzwerks nicht existieren sollte: localhost, 127.0.0.1, 0.0.0.0, die privaten IP-Bereiche 10.x.x.x, 192.168.x.x und 172.16.x.x bis 172.31.x.x, sowie jede Domain, die auf .local endet. Findet er welche, öffnet er einen Befund mit niedrigem Schweregrad und den ersten Verweisen. Untersucht wird nur das anfängliche HTML; was JavaScript danach aufbaut, wird auf diesem Weg nicht gesehen.
Warum das wichtig ist
Ein Verweis auf http://localhost:3000/api/... in Produktion hat zwei Folgen. Die erste ist funktional: Für deinen Nutzer ist localhost sein eigener Rechner, also lädt dieses Bild nicht, dieses Formular geht ins Leere und dieses Skript scheitert still. Die zweite betrifft Information: Du erzählst jedem, dass deine API auf Port 3000 läuft, dass dein internes Backend api.firma.local heißt oder dass dein Netz den Bereich 10.0.1.x nutzt. Nichts davon ist für sich ein ausnutzbarer Fehler, daher der niedrige Schweregrad, aber es sind Puzzleteile, die ein Angreifer für später aufhebt, und sie verraten, dass das Deployment ohne Durchsicht rausging.
Warum das passiert
Fast immer ist es eine während der Entwicklung von Hand getippte URL, die niemand geändert hat. Die KI, die das Projekt erzeugt hat, schrieb http://localhost:8000 in den fetch des Formulars oder in das src eines Testbilds, lokal funktionierte es, also blieb es. Andere Ursachen: eine Entwicklungs-.env, die im Produktions-Build gelandet ist, ein aus einer lokalen Umgebung migriertes WordPress mit nicht aktualisierter Site-URL, oder eine Formular-action, die aus einem Beispiel kopiert wurde.
So behebst du es
- Nimm die URLs aus dem Code. Die Basis deiner API gehört in eine Umgebungsvariable (
NUXT_PUBLIC_API_BASE,NEXT_PUBLIC_API_URL,VITE_API_URL) mit einem eigenen Wert pro Umgebung. In Produktion injiziert die Plattform (Vercel, Netlify, Railway) sie beim Build. - Nutze relative Pfade, wann immer die Ressource auf deiner eigenen Domain liegt:
/api/kontaktstatthttp://localhost:3000/api/kontakt. Sie funktionieren lokal und in Produktion gleich. - WordPress: aktualisiere die Site-URLs unter Allgemeine Einstellungen und ersetze die alten URLs in der Datenbank mit einem Werkzeug, das die Serialisierung respektiert.
- Such im Build, bevor du deployst. Ein CI-Schritt, der fehlschlägt, wenn die kompilierte Ausgabe diese Hosts enthält, packt das Problem an der Wurzel:
grep -rEl "localhost|127\.0\.0\.1|192\.168\.|\.local\b" dist/ .output/public/ 2>/dev/null
Kommt eine Datei heraus, gibt es einen Verweis, der vor dem Ausliefern zu korrigieren ist.
Prüf, ob es behoben ist
curl -s https://deinedomain.de | 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"
Es darf nichts herauskommen. Probier auch ein oder zwei Unterseiten, vor allem solche mit Formularen.
Häufige Fragen
Es ist ein Testbild, das niemand sieht. Spielt das eine Rolle?
Der Browser jedes Besuchers versucht, es vom eigenen Rechner zu laden, und das HTML kündigt weiter deinen internen Host an. Ändere oder lösche es; das dauert eine Minute.
Wird das kompilierte JavaScript auch geprüft?
Von dieser Prüfung nicht, nur das HTML. Aber eine interne URL im Bundle kommt meist zusammen mit anderen Dingen, die dort nicht hingehören; Geheimnisse im JavaScript sucht Schlüssel und Tokens, und HTML-Kommentare sucht Reste im HTML selbst. Die drei zusammen decken ab, was von einer Entwicklungsumgebung üblicherweise übrig bleibt.
Mein Link zeigt absichtlich auf eine .local-Domain.
.local-Domains sind für lokale Netze (mDNS) reserviert und lösen im Internet nicht auf. Willst du ein internes Werkzeug verlinken, nutze eine echte Subdomain mit Authentifizierung. Was deine App unabsichtlich preisgibt, mit weiteren Beispielen, steht in Geheimnisse, die deine App im Browser preisgibt.