dotvitals

A redirect pointed somewhere the scanner will not follow

MediumConfirmedhttp.redirects.hop-refused

What this check looks for

One step of the chain led to an address we refuse to connect to — a private network address, a cloud metadata endpoint, or an internal-only name. We stopped there.

Why it matters

Part of the chain was not measured, so the report is incomplete. More importantly, a public URL that redirects into private address space is the exact shape of an open redirect being used to reach infrastructure that should not be reachable from outside.

When the check passes, your report says: “Every hop led somewhere we were able to follow”.

What it costs your score

When this check fails it removes 12 points from your HTTP score, before the status, confidence and repeat multipliers are applied. HTTP carries a weight of 7 in the overall score.

It shares the http.redirects family ceiling of 45 points: however many findings that family produces, together they cannot remove more than that from HTTP. One underlying problem showing up in several places is still one problem.

Severity
medium
Default confidence
confirmed
Status when triggered
warn
Deduction
12 points
Family cap
http.redirects · 45
Category
HTTP
Module
Http redirects
Fix owned by
user
In the ruleset since
2026.09

How the whole score is calculated

How to fix it

Make sure no publicly reachable URL redirects into private address space.

It leaves part of the site unmeasurable and is the signature of an open redirect.

  1. Find the rule producing this destination and confirm it was intended.

  2. If the redirect target comes from a request parameter, validate it against an allow-list of permitted destinations rather than a pattern.

  3. If the internal address is deliberate, restrict the endpoint so it is not reachable from outside.

How to confirm it worked

  • curl -sSI https://‹host›/ | grep -i '^location:' — the target should be a public address

A named slot like ‹domain› — and the braces left in the configuration below — is filled in with your own values when this rule appears on a report.

Remediation by platform

nginx
# One hop, straight to the canonical origin. Not http -> https -> www -> path.
server {
	listen 80;
	listen 443 ssl;
	server_name ‹host›;
	return 301 https://www.‹host›$request_uri;
}
Apache
<VirtualHost *:80 *:443>
	ServerName ‹host›
	RedirectMatch 301 ^/(.*)$ https://www.‹host›/$1
</VirtualHost>
Caddy
‹host› {
	redir https://www.‹host›{uri} permanent
}
Cloudflare
Rules → Overview → Create rule → Redirect Rule (path as at 2026-09) → single rule: When hostname equals ‹host›, Static/Dynamic redirect to https://www.‹host›/${http.request.uri.path}, status 301, preserve query string.
  • Collapse the chain into a single redirect per source host rather than chaining them.

  • Shown because the response identified Apache. Prefer the virtual host over .htaccess: .htaccess is re-read on every request and its rules run after the virtual host's, which is how these chains get long in the first place.

  • Cloudflare Redirect Rules run at the edge and apply only to requests that arrive through it. An origin reachable directly — by IP, or through a DNS record that is not proxied — still produces the chain measured here. Fix the origin's own configuration as well.

Technical detail

‹detail›

The scanner validates every hop before connecting: scheme, userinfo, hostname, public-suffix, and the resolved address against the private, loopback, link-local, CGNAT and cloud-metadata ranges. A refusal is reported rather than followed. If the destination is genuinely internal, the redirect should not be reachable from the public internet in the first place; if it is unintentional, it is a redirect built from unvalidated input.

Standards and references

Test this on your domain

Run the check that produces this finding, on its own, against any domain.

Open the http redirects checkerBuild the fix

Other http redirects checks