Referrer-Policy: stop leaking URLs (and tokens) to other sites
Here's a leak that hides in plain sight. Every time someone on your site clicks a link to another site — or your page loads an image, script or font from a third party — the browser can tell that other server exactly which page of yours the user was on. The full URL. If anything sensitive is sitting in that URL, you just handed it to someone else's logs. The Referrer-Policy header is how you control that, and it's one of the quickest security headers to get right.
What actually leaks
When a browser makes a request triggered by your page, it may attach a Referer header (yes, misspelled — a 1990s typo enshrined in the spec forever) naming the URL the request came from. That's useful for analytics, and mostly harmless — until your URLs contain things they shouldn't. The classic disasters:
- A password-reset link like
/reset?token=abc123. The page loads a third-party script or the user clicks an outbound link, and that token lands in someone else's server logs. - A page with a session ID, invite code, or signed URL in the query string.
- An internal URL that quietly reveals account IDs, email addresses, or your app's structure to every analytics and ad pixel on the page.
None of this throws an error. It's a silent, continuous outflow, and most teams never notice it's happening.
The modern default (and why you shouldn't just trust it)
The good news: browsers got much saner about this. When your site sends no policy at all, current browsers default to strict-origin-when-cross-origin. Under that default:
- Navigating within your own site (same-origin) sends the full URL.
- Going to another site (cross-origin) sends only your origin —
https://yoursite.com, no path, no query. - Going from an HTTPS page to an HTTP one sends nothing.
That's a reasonable baseline. But "the browser's default is fine" isn't a security posture — it means you're trusting every browser version your users run, you've set no explicit intent, and you have nothing stricter on the pages that actually need it. I'd rather state the policy myself, as a header, so it's deliberate and auditable like any other security header.
The values, from loosest to strictest
| Value | What it sends |
|---|---|
unsafe-url | Full URL, always, everywhere — including HTTPS→HTTP. Don't use this. |
no-referrer-when-downgrade | Full URL except on HTTPS→HTTP. The old default; too loose now. |
origin | Only your origin, to everyone, always. |
origin-when-cross-origin | Full URL same-origin, origin only cross-origin. |
strict-origin-when-cross-origin | Like above, but sends nothing on HTTPS→HTTP. The modern default and a solid baseline. |
same-origin | Full URL to your own site, nothing to any other site. |
strict-origin | Only your origin, and nothing on HTTPS→HTTP. |
no-referrer | Never send a referrer at all. |
What I'd actually set
Keep it simple. Send a site-wide header as your baseline:
Referrer-Policy: strict-origin-when-cross-origin
Then tighten the pages whose URLs can carry secrets. On a password-reset route, account settings, or anything with a token or ID in the path, drop to same-origin or no-referrer. You can set it per-response on the server, or per-element in HTML (a referrerpolicy attribute on a specific link or image), but a sensible global header plus a stricter override on sensitive routes covers almost everyone.
The part most posts skip
Referrer-Policy reduces the blast radius. It does not fix the underlying mistake. If a password-reset token or a session ID is in your URL in the first place, the header is damage control — it just narrows who you leak it to. The real fix is to keep secrets out of URLs: put tokens in the request body or short-lived, single-use, and out of the query string.
So treat the header as the belt and the URL hygiene as the suspenders. Set Referrer-Policy because it's cheap and it closes a real leak to analytics and ad networks — and separately, audit whether anything sensitive is riding in your URLs at all. There's a privacy-law angle too: leaking account identifiers or emails to third-party domains through the referrer is exactly the kind of incidental data sharing a GDPR review is meant to catch.
Like every header, this one is invisible until you check for it, and a deploy or CDN change can silently drop it. The only way to know Referrer-Policy is actually set — and set the way you intended — is to read your live response headers from outside, and keep reading them.
Check your security headers in seconds
Perimeter inspects your Referrer-Policy and the rest of your security headers — Content-Security-Policy, HSTS, X-Frame-Options and more — alongside your TLS, DNS and accessibility posture. And it re-checks on a schedule, so a header a deploy quietly drops gets flagged before it becomes a standing leak. Free, no signup.
Monitor your headers → · Agency plan $29/mo, up to 25 domains