Website problems

Internal URLs in public code

Served scripts and stylesheets frequently contain URLs that were never meant to leave the build: internal hostnames, staging addresses, administrative endpoints, service names from a private network. None of them is a credential and none is a way in. Together they describe your infrastructure to a reader who had no map of it, which is the difference between an attacker guessing and an attacker reading.

What ends up in a bundle

Internal hostnames resolving only inside a private network, left in a configuration object that is bundled wholesale.

Staging and development endpoints, usually alongside the production one in the same object.

Administrative paths, referenced by a script that checks whether the current user is an administrator.

Service names and internal port numbers, in comments or in error-handling code.

Cloud resource identifiers, which name the account, the region and frequently the service.

Why it matters even though nothing is reachable

An internal hostname is not reachable from outside, and it tells a reader the naming convention for everything else.

A staging endpoint frequently is reachable, runs the same application with older dependencies, and has weaker access controls.

An administrative path tells a reader exactly where to direct credential attempts.

Cloud identifiers reduce the search space for anything else that account exposes.

Individually each is minor, which is why none of them ever gets removed; together they are the reconnaissance step done for free.

How the values get bundled

A single configuration module holding every environment's settings, imported by code that only needs one of them.

A build that inlines the whole configuration rather than the subset the browser needs.

Dead code paths referencing endpoints that are no longer used, which the bundler keeps because it cannot prove they are unreachable.

Comments describing an internal process, which minification usually removes and source maps restore.

A generated client from an internal specification, which includes every endpoint the specification described.

How to fix it

Split configuration so the browser build receives only what the browser needs, rather than the whole object.

Select environment values at build time rather than shipping all of them and choosing at runtime.

Remove dead code paths referencing endpoints no longer in use, which is worth doing for size as well.

Stop serving source maps publicly, or upload them to an error-reporting service instead — they restore comments and original names.

Add a check to the build that fails on known internal domain suffixes appearing in browser output.

What to do about the staging endpoint specifically

Find out whether it is publicly reachable, which it usually is on a predictable hostname.

Put authentication in front of it. Nothing else reliably prevents access, and a robots directive prevents neither access nor indexing.

Check whether it is indexed, since a reachable staging copy serving real content ends up in search results.

Confirm it does not share a database or credentials with production, which is the case that turns reconnaissance into consequence.

How to check it yourself

Download your main bundle and search it for your internal domain suffix, for the word staging, and for administrative path fragments.

Search for cloud resource identifier patterns, which are recognisable and specific.

Do the same on the source map if one is served, since it restores comments and original variable names.

Check stylesheets too, which reference hosts in image and font URLs.

Repeat after each release, since a bundle's content changes with every dependency and configuration change.

How VeriFixScan detects it

`exposure.internal.urls` reports internal URLs found in public assets, and `exposure.internal.paths` reports absolute server paths.

`exposure.comments.sensitive` reports revealing comments left in served code.

`exposure.sourcemap.public` and `exposure.sourcemap.sources_content` report whether maps are served and whether they embed the original source.

`devops.secondary_environments` reports secondary environments referenced publicly, which is where a staging endpoint appears.

`exposure.assets.coverage` states how much of the asset inventory was inspected, which is what keeps a clean result honest.

Why stylesheets are worth reading too

Stylesheets reference hosts in image, font and import URLs, and those references survive minification as string values.

A font or image served from an internal asset host names that host in every stylesheet that uses it.

Imports pull in further stylesheets, each of which can reference hosts of its own, so the surface is larger than the main file suggests.

Inline styles in the served markup carry the same references and are frequently missed because nobody thinks of them as code.

Which is why the asset inspection covers stylesheets alongside scripts rather than treating them as presentation only.

Frequently asked questions

Is an internal hostname really a problem if it does not resolve publicly?
On its own it is minor. It reveals your naming convention, which makes everything else easier to guess — and it usually appears alongside a staging endpoint that is reachable.
Does minification remove this?
It removes comments and shortens names. URLs are string values and survive minification intact — and a served source map restores the comments anyway.
What should I do first?
Check whether any referenced staging endpoint is publicly reachable, and put authentication in front of it. The bundle cleanup matters and is less urgent than that.

Sources

Related

VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.

Scan a website