Every time a user clicks from your app to a third-party link, the browser may send a Referer header with the full URL they came from—including path segments, query strings and sometimes one-time tokens. Password-reset links, signed download URLs, invite codes and internal admin paths have all leaked this way into analytics vendors, CDNs and support widgets. Referrer-Policy is the response header that decides how much of that URL other origins are allowed to see. Set it wrong (or leave the browser default) and you quietly ship secrets to whoever sits at the other end of the click.
I build PixelValut, a set of browser-side developer and security tools, and I wanted a practical checklist for teams that already ship HTTPS but never audited what their pages put in Referer. I wrote this with help from AI tools and checked every command and claim myself. This piece covers the policy values that matter, real leak scenarios, how to set and verify the header with curl and DevTools, and a safe default for most SaaS apps.
What does Referrer-Policy actually control?
Direct answer: Referrer-Policy tells browsers how much of the current page URL to put in the Referer header (and in document.referrer) when the user navigates or loads a subresource. Policies range from sending nothing (no-referrer) to sending the full URL even on HTTPS→HTTP downgrades. Pick a value that keeps path and query off cross-origin requests unless you truly need them for analytics.
The policy values in one table
| Policy | Same-origin request | Cross-origin HTTPS→HTTPS | HTTPS→HTTP downgrade | Typical use |
|---|---|---|---|---|
no-referrer | No Referer | No Referer | No Referer | Highest privacy; breaks referrer-based analytics |
no-referrer-when-downgrade | Full URL | Full URL | No Referer | Old browser default; still leaks path/query cross-origin |
origin | Origin only | Origin only | Origin only | Soft analytics without paths |
origin-when-cross-origin | Full URL | Origin only | Origin only | Good balance for many apps |
same-origin | Full URL | No Referer | No Referer | Strict; third parties see nothing |
strict-origin | Origin only | Origin only | No Referer | Origin for peers; strip on downgrade |
strict-origin-when-cross-origin | Full URL | Origin only | No Referer | Current browser default on modern engines; solid SaaS default |
unsafe-url | Full URL | Full URL | Full URL | Almost never justified |
Modern Chrome, Firefox and Safari effectively default to strict-origin-when-cross-origin when the site sends no policy. That is better than the old no-referrer-when-downgrade default, but it still sends your full path and query to other pages on the same origin, and your origin (scheme + host + port) to other HTTPS sites. If a reset link lives at https://app.example.com/reset?token=… and the user clicks a cross-origin help article, the token stays off the wire—only https://app.example.com/ is sent. If that help widget is same-site or you used unsafe-url, the token can leave the browser.
Leak scenarios worth designing against
Treat these as design cases, not one-off bugs:
- Password-reset and magic-login URLs in emails. User opens the link, then clicks to an external status page or chatbot. Cross-origin navigations under a strict policy omit the query; a loose policy or a same-origin redirect chain can still expose it in logs.
- Signed download or S3-style URLs pasted into a webview that then loads third-party fonts, iframes or error beacons. Subresource requests also send
Refererunless the policy strips them. - Invite and share links with capability tokens in the query string. A recipient forwards the page; analytics on an outbound link inherits the referrer.
- Internal admin paths (
/admin/users/123/impersonate). Even without tokens, path leakage tells an external script who you were looking at. - Mixed content and HTTP images on an HTTPS page. Downgrade rules matter;
unsafe-urland older defaults are how full URLs end up on cleartext hops.
This sits next to transport controls like MTA-STS for inbound email and certificate issuance limits via CAA records and CT logs: each closes a different disclosure channel. Referrer policy closes the browser-navigation channel.
Weak vs hardened header setups
| Weak | Hardened | Why |
|---|---|---|
No Referrer-Policy header | Referrer-Policy: strict-origin-when-cross-origin | Explicit beats relying on each browser's default |
unsafe-url "so analytics works" | origin or strict-origin-when-cross-origin plus server-side UTM on outbound links you control | You do not need full paths in third-party logs |
| Token in query on a marketing page that loads many third-party scripts | Move secrets to POST body, fragment, or one-time server session; keep same-origin or no-referrer on that route | Headers cannot fix a secret that must never leave |
Only a <meta name="referrer"> on some templates | Send the HTTP header globally from the reverse proxy or app middleware | Meta tags are easy to forget on error pages and APIs |
| Different policies per environment, undocumented | One documented default in nginx/Cloudflare/Laravel, with per-route exceptions listed | Drift is how unsafe-url survives in staging clones |
Set the header in nginx, Cloudflare and Laravel
Nginx (inside the server block):
add_header Referrer-Policy "strict-origin-when-cross-origin" always; Cloudflare Transform Rule or Response Header modification:
Set Referrer-Policy = strict-origin-when-cross-origin Laravel middleware (global):
public function handle($request, Closure $next) { $response = $next($request); $response->headers->set( 'Referrer-Policy', 'strict-origin-when-cross-origin' ); return $response; } You can also set a document-wide default with HTML, useful on static sites:
<meta name="referrer" content="strict-origin-when-cross-origin"> Prefer the HTTP header for APIs and redirects. For a single sensitive view (reset confirm, billing portal), tighten further:
Referrer-Policy: no-referrer HTML links can override per navigation with the referrerpolicy attribute or rel="noreferrer":
<a href="https://partner.example/docs" referrerpolicy="no-referrer">Docs</a> <a href="https://partner.example/docs" rel="noreferrer">Docs</a> rel="noreferrer" also implies noopener behavior for browsing context, which pairs well with the reverse-proxy hardening patterns in zero-trust nginx setups.
Verify with curl, DevTools and PixelValut
Check that the response advertises the policy:
curl -sI https://pixelvalut.com/tools/ | grep -i referrer-policy You want a line like:
referrer-policy: strict-origin-when-cross-origin In Chrome DevTools:
- Open Network, click the document request, read Response Headers for
referrer-policy. - Click an outbound request to a third party and inspect Request Headers →
referer. - Confirm cross-origin calls show only the origin (or nothing), never
?token=or/reset/.
For a quick browser-side pass on any URL, use the PixelValut HTTP Status Checker to inspect response headers without installing anything. Then repeat the navigation test in DevTools—header presence alone does not prove outbound requests are stripped; you still need to watch a real cross-origin click.
What Referrer-Policy does not fix
| Problem | Why policy is not enough | Better control |
|---|---|---|
| Secret in the URL bar copied by the user | No browser header involved | Prefer body/fragment/session; short TTL tokens |
| Server-side logs of your own full URLs | Same-origin full referrers still apply under several policies | Redact query strings in access logs |
Third-party script reading document.referrer same-origin | Policy allows full URL same-origin by design under the recommended default | no-referrer / same-origin on sensitive pages; CSP script allowlists |
| Email clients prefetching links | Different client stack | Single-use tokens; do not put long-lived secrets in query strings |
Rollout checklist
- [ ] Choose a site-wide default: start with
strict-origin-when-cross-origin - [ ] Send it as an HTTP response header from the edge or app (not only a meta tag)
- [ ] Tighten reset, invite and billing routes to
no-referrerorsame-origin - [ ] Ban
unsafe-urlin code review and config lint - [ ] Move capability tokens out of query strings where you can
- [ ] Verify with
curl -sIand a DevTools cross-origin click - [ ] Spot-check staging and error pages—they often miss global middleware
- [ ] Document outbound links that truly need origin-level analytics
Frequently asked questions
Is strict-origin-when-cross-origin safe enough for SaaS?
For most product apps, yes as a default. It keeps path and query off cross-origin requests and strips referrers on HTTPS→HTTP downgrades. Sensitive flows (password reset, impersonation, billing) still deserve no-referrer or same-origin.
Will this break Google Analytics or ads?
It can reduce the path-level detail third parties receive. Origin-only or missing referrers are common under modern defaults. If you need campaign attribution, put UTM parameters on links you control and accept that full-path referrers to arbitrary third parties are not worth the leak.
What is the difference between Referrer-Policy and rel="noreferrer"?
The header (or meta tag) sets a document default. rel="noreferrer" and the referrerpolicy attribute override per link. Use the header globally, then override on specific outbound anchors.
Does Referrer-Policy affect APIs and fetch calls?
Yes. fetch, XHR and subresources send Referer according to the policy (and the request's referrerPolicy option). A global header covers navigations and most subresources; explicit referrerPolicy: "no-referrer" in fetch helps for sensitive XHRs.
Should I use no-referrer everywhere?
You can, if you do not rely on inbound referrers for security or analytics. Many teams prefer strict-origin-when-cross-origin site-wide and no-referrer only on secret-bearing pages so first-party analytics still see full same-origin paths.
How do I test a leak before changing production?
Open a staging page whose URL contains a dummy ?token=test, click a cross-origin link or load a cross-origin image, and inspect the outbound Referer in DevTools. Repeat after setting the header until the token disappears from cross-origin requests.
Follow & Connect
- YouTube: PixelValut (@pixel-valut)
- TikTok: PixelValut (@pixelvalut007)
- GitHub: Muhammad Ali Mughal (@ali111887)
- LinkedIn: Muhammad Ali Mughal

