Loose Referrer Policy (no-referrer-when-downgrade) Detected
Issue No: 112
Category: Html Head Tags
Issue type: Warning
Priority: Important
Description
The no-referrer-when-downgrade referrer policy causes browsers to send the full URL (including path and query string) in the HTTP Referer header for cross-origin HTTPS-to-HTTPS requests. This was the browser default prior to Chrome 85 (2020). Modern browsers now default to strict-origin-when-cross-origin, which sends only the origin (e.g. https://example.com) instead of the full URL (https://example.com/page?token=abc123). Explicitly setting the old loose policy overrides the modern default and leaks sensitive URL parameters to third-party destinations.
How do we capture it
-
Check the HTTP
Referrer-Policyresponse header for each crawled page:- Extract the header value.
- Record
referrer_policy_header.
-
Check for
<meta name="referrer">in the page<head>:- Extract the
contentattribute value. - Record
referrer_meta_value.
- Extract the
-
Determine the effective policy:
- HTTP response header takes precedence over the meta tag.
- If the header is absent, the meta tag is effective.
- If neither is present, the effective policy is the browser default (
strict-origin-when-cross-origin). - Record
effective_policy.
-
Classify the policy:
- Mark
is_no_referrer_when_downgrade = trueif the effective policy is exactlyno-referrer-when-downgrade. - Mark
is_loose_policy = trueif the effective policy isno-referrer-when-downgradeorunsafe-url. - Mark
is_valid_value = falseif the value is not in the set of valid Referrer-Policy tokens.
- Mark
-
Detect conflicts:
- If both the HTTP header and meta tag are present and differ, set
has_conflict = true.
- If both the HTTP header and meta tag are present and differ, set
-
Scan the URL and query string for sensitive parameters:
- Check the current page's URL query string for common sensitive parameter names.
- Sensitive parameter patterns:
token,key,api_key,auth,session,secret,password,access_token,refresh_token,code,state,nonce,utm_prefixed params with PII patterns. - Record
url_has_sensitive_params = trueand list the parameter names insensitive_params.
What to store
| Field | Type | Comment |
|---|---|---|
site_id | integer | FK → sites(id) |
page_id | integer | FK → pages(id) |
referrer_meta_present | boolean | Whether <meta name="referrer"> exists in <head> |
referrer_meta_value | text | content value of the referrer meta tag; NULL if absent |
referrer_policy_header | text | Value of the Referrer-Policy HTTP response header; NULL if absent |
effective_policy | text | The resolved policy (header > meta > browser default) |
is_no_referrer_when_downgrade | boolean | Whether effective policy is exactly no-referrer-when-downgrade |
is_loose_policy | boolean | Whether effective policy is no-referrer-when-downgrade or unsafe-url |
is_valid_value | boolean | Whether effective policy is a recognised Referrer-Policy token |
has_conflict | boolean | Whether HTTP header and meta tag declare different policies |
url_has_sensitive_params | boolean | Whether the page URL contains sensitive query parameters |
sensitive_params | text[] | List of detected sensitive parameter names in the URL |
checked_at | timestamp | When this check was last performed |
Condition for trigger
The following rules evaluate stored fields and produce diagnostics in the audit report.
-
Trigger Rule 1: Loose Policy (
no-referrer-when-downgrade)- Target Field:
is_no_referrer_when_downgrade - Evaluation Logic:
is_no_referrer_when_downgrade = true AND url_has_sensitive_params = false - Severity: WARNING
- Diagnostic Message: "The referrer policy is set to
no-referrer-when-downgrade, which sends the full URL (including path and query string) to cross-origin HTTPS destinations via theRefererheader. The modern browser default (strict-origin-when-cross-origin) sends only the origin. Update the policy tostrict-origin-when-cross-originor stricter."
- Target Field:
-
Trigger Rule 2: Loose Policy With Sensitive URL Parameters
- Target Field:
is_loose_policy,url_has_sensitive_params - Evaluation Logic:
is_loose_policy = true AND url_has_sensitive_params = true - Severity: CRITICAL
- Diagnostic Message: "The referrer policy is
[effective_policy]and the page URL contains sensitive parameters ([sensitive_params]). These parameters are being leaked in theRefererheader to every cross-origin resource loaded on this page (analytics, ads, fonts, CDN assets). Change the policy tono-referrerorstrict-originimmediately."
- Target Field:
-
Trigger Rule 3: Meta Tag and HTTP Header Conflict
- Target Field:
has_conflict - Evaluation Logic:
has_conflict = true - Severity: CRITICAL
- Diagnostic Message: "The
Referrer-PolicyHTTP header ([referrer_policy_header]) and<meta name=\"referrer\">tag ([referrer_meta_value]) declare different policies. The HTTP header takes precedence. Remove the conflicting meta tag or align both to the same intended policy."
- Target Field:
-
Trigger Rule 4: Invalid Referrer Policy Value
- Target Field:
is_valid_value - Evaluation Logic:
is_valid_value = false AND effective_policy IS NOT NULL - Severity: WARNING
- Diagnostic Message: "The referrer policy value
[effective_policy]is not a valid Referrer-Policy token. Browsers will ignore an invalid value and fall back to the default policy. Use a valid value:no-referrer,no-referrer-when-downgrade,origin,origin-when-cross-origin,same-origin,strict-origin,strict-origin-when-cross-origin, orunsafe-url."
- Target Field:
-
Trigger Rule 5:
unsafe-urlPolicy Detected- Target Field:
effective_policy - Evaluation Logic:
effective_policy = 'unsafe-url' - Severity: CRITICAL
- Diagnostic Message: "The referrer policy is set to
unsafe-url, which sends the full URL (including path, query string, and any sensitive parameters) for ALL requests — including HTTP (downgrade) requests. This is the most permissive policy and leaks sensitive URL data broadly. Replace withstrict-origin-when-cross-originat minimum."
- Target Field:
Sources
- W3C Referrer Policy specification: https://www.w3.org/TR/referrer-policy/
- MDN —
Referrer-PolicyHTTP header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy - Google web.dev — Referrer best practices: https://web.dev/articles/referrer-best-practices
- Chrome 85 change — New default Referrer-Policy: https://developers.google.com/web/updates/2020/07/referrer-policy-new-chrome-default
- OWASP — HTTP Security Headers: https://owasp.org/www-project-secure-headers/
- MDN —
<meta name="referrer">: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name#referrer
Long description
The HTTP Referer header (note the historical misspelling) is sent by browsers on each request and tells the server the URL of the page that initiated the request. This header is used by analytics platforms, advertising networks, and CDNs to understand referral traffic. The Referrer-Policy governs how much of the originating URL is included in that header.
Policy comparison table
| Policy | Sent to same-origin | Sent to cross-origin HTTPS | Sent to HTTP (downgrade) |
|---|---|---|---|
no-referrer | Nothing | Nothing | Nothing |
strict-origin | Origin only | Origin only | Nothing |
strict-origin-when-cross-origin (modern default) | Full URL | Origin only | Nothing |
origin-when-cross-origin | Full URL | Origin only | Nothing |
origin | Origin only | Origin only | Origin only |
no-referrer-when-downgrade (old default) | Full URL | Full URL | Nothing |
unsafe-url | Full URL | Full URL | Full URL |
The key distinction is between "origin only" (https://example.com) and "full URL" (https://example.com/path?token=secret). The no-referrer-when-downgrade policy sends the full URL to cross-origin HTTPS destinations — meaning every third-party resource load (fonts, analytics scripts, CDN assets) receives the full URL including all query parameters.
Why this changed in Chrome 85
Chrome 85 (August 2020) changed the browser default from no-referrer-when-downgrade to strict-origin-when-cross-origin. Firefox and Safari followed. Sites that explicitly set no-referrer-when-downgrade now need to do so deliberately — the browser no longer silently applies the loose policy. Explicitly declaring the old loose policy is a regression to less safe behaviour.
Sensitive parameter leakage scenario
Consider a checkout page: https://shop.example.com/checkout?session_id=abc123&return_token=xyz789. If the page loads a Google Font, a Stripe payment script, and a Google Analytics tag, all three receive a request with Referer: https://shop.example.com/checkout?session_id=abc123&return_token=xyz789. The session_id and return_token values are now visible to three separate third parties.
Recommended policy
For most sites: strict-origin-when-cross-origin. This is the modern browser default and provides a good balance:
- Same-origin requests get the full URL (preserving internal analytics accuracy).
- Cross-origin requests get only the origin (preventing parameter leakage to third parties).
- No data is sent on HTTP downgrade requests.
Common failure patterns:
- The policy was explicitly set years ago to maintain referral analytics accuracy and was never updated when browsers changed their defaults.
- A third-party tag manager or analytics script injects a meta tag that sets
no-referrer-when-downgrade. - The policy conflicts between the HTTP header (set by a WAF or CDN rule) and the HTML meta tag (set in the page template).
unsafe-urlwas set during debugging and was never reverted to a safe value.- No policy is explicitly set and the browser default is assumed to be
no-referrer-when-downgrade, which is no longer true in modern browsers.
How to Fix
-
Set the
Referrer-PolicyHTTP response header at the server or CDN level:- Apache:
Header always set Referrer-Policy "strict-origin-when-cross-origin" - Nginx:
add_header Referrer-Policy "strict-origin-when-cross-origin" always; - CDN (Cloudflare, etc.): add the header via a Transform Rule or Page Rule.
- Setting the header at the server level means it applies to all pages automatically.
- Apache:
-
Remove or update the
<meta name="referrer">tag if it sets a loose policy:- If you want a consistent sitewide policy, set it via the HTTP header and remove the meta tag entirely.
- If you need per-page policy overrides, use the meta tag to set a stricter policy on sensitive pages (e.g.
no-referreron checkout pages).
-
For pages with sensitive URL parameters, use
no-referrerorstrict-originto ensure parameters are never leaked:<meta name="referrer" content="no-referrer">on checkout, authentication callback, and password-reset pages.
-
Audit third-party scripts that may inject
<meta name="referrer">tags via tag manager. Check the tag manager container for any referrer policy overrides. -
Verify the effective policy using browser DevTools:
- Open Network tab → click any cross-origin request → inspect the
Refererrequest header. - Confirm it shows only the origin (e.g.
https://example.com) and not the full path with parameters.
- Open Network tab → click any cross-origin request → inspect the
-
Test that analytics are not broken: after changing the policy, verify that referral traffic reporting in Google Analytics / Matomo still works.
strict-origin-when-cross-originpreserves theRefererheader for cross-origin HTTPS requests (origin only), so direct referral source tracking remains functional.
Additional technical notes
Referrer-Policy via <link> element
In addition to the HTTP header and <meta> tag, individual <a> and <link> elements can carry a referrerpolicy attribute that overrides the page-level policy for that specific link or resource:
<a href="https://external.com" referrerpolicy="no-referrer">Visit</a>
This per-element override is useful for links to sensitive external destinations where the page-level strict-origin-when-cross-origin policy still sends the origin but you want no referrer sent at all.
Referrer-Policy and analytics impact
Changing from no-referrer-when-downgrade to strict-origin-when-cross-origin may cause changes in analytics referral data:
- Internal traffic referral: same-origin requests still receive the full URL, so internal analytics are unaffected.
- External referrals TO this site: not affected — this policy governs what the current page sends, not what incoming traffic reports.
- Outbound referrals FROM this site to third-party analytics tools: only the origin is sent, not the full path. This can reduce granularity in tools that read the
Refererheader to attribute traffic sources. - Google Analytics via its own JS tag: GA uses its own measurement protocol and does not rely on the
Refererheader for standard page view tracking. Changing the policy does not affect GA data collection.
OWASP recommendation
The OWASP Secure Headers Project lists Referrer-Policy: strict-origin-when-cross-origin as the recommended default. It is included in the OWASP HTTP Security Headers cheat sheet as a baseline requirement for all web applications. Sites without an explicit policy (or with a loose policy) fail OWASP header compliance checks.
Policy inheritance and nested iframes
The Referrer-Policy HTTP header and <meta> tag apply to the document they are served with. Nested iframes are governed by their own document's policy, not the parent frame's policy. For embedded third-party content (payment iframes, chat widgets), the embedded document's own origin server controls the referrer policy for requests it initiates.
Validation checklist
Before marking this issue resolved, confirm all of the following:
-
curl -I {url}output includesReferrer-Policy: strict-origin-when-cross-origin(or stricter). - No
<meta name="referrer" content="no-referrer-when-downgrade">is present on any page. - No
<meta name="referrer" content="unsafe-url">is present on any page. - Pages with sensitive URL parameters use
no-referrerorstrict-originpolicy. - Browser DevTools confirms cross-origin requests show only the origin in the
Refererheader, not the full URL with parameters.