A redirect destination is malformed
What this check looks for
The address the server redirected to is not a usable web address. Browsers may refuse it, or may interpret it in a way you did not intend.
Why it matters
Two parsers reading the same malformed address differently is the mechanism behind a whole class of redirect attacks. Even when it is only a bug, the affected URLs do not work.
When the check passes, your report says: “Every redirect destination is a usable web address”.
What it costs your score
When this check fails it removes 20 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
- fail
- Deduction
- 20 points
- Family cap
- http.redirects · 45
- Category
- HTTP
- Module
- Http redirects
- Fix owned by
- user
- In the ruleset since
- 2026.09
How to fix it
Emit a well-formed absolute URL, built by a URL library rather than by string concatenation.
A malformed destination is where a redirect becomes an attack surface rather than a bug.
Build the target with the platform's URL type instead of concatenating strings.
Percent-encode anything that came from the request before it goes into the target.
Never place user input in the
Locationheader without validating it against an allow-list of destinations.
How to confirm it worked
curl -sSI https://‹host›/ | grep -i '^location:' — expect a clean absolute URL
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
# 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;
}<VirtualHost *:80 *:443>
ServerName ‹host›
RedirectMatch 301 ^/(.*)$ https://www.‹host›/$1
</VirtualHost>‹host› {
redir https://www.‹host›{uri} permanent
}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 checks that reject a destination are the ones that exist because parsers disagree: a control character or newline in the header (response-splitting residue), a backslash — which WHATWG folds to / inside an authority, so /\10.0.0.1 becomes a *host* — a scheme other than http or https, and a value past the length cap. None of these is repaired, because a repaired URL is one nobody actually sent.
Standards and references
Test this on your domain
Run the check that produces this finding, on its own, against any domain.