惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
T
ThreatConnect
SecWiki News
SecWiki News
F
Future of Privacy Forum
AWS News Blog
AWS News Blog
C
Cisco Blogs
A
Arctic Wolf
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
V2EX
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
K
Kaspersky official blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
NISL@THU
NISL@THU
Microsoft Azure Blog
Microsoft Azure Blog
量子位
The Hacker News
The Hacker News
Stack Overflow Blog
Stack Overflow Blog
Security Latest
Security Latest
M
Microsoft Research Blog - Microsoft Research
Google Online Security Blog
Google Online Security Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
InfoQ
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
F
Fox-IT International blog
S
Security @ Cisco Blogs
博客园 - 司徒正美
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Comments on: Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LINUX DO - 最新话题
GbyAI
GbyAI
Project Zero
Project Zero
腾讯CDC
T
Tailwind CSS Blog

DEV Community

Bajándole todos los minutos posibles al CI del backend con mas de 1000 tests Harness Engineering: Stop Re-Prompting Your Coding Agent Every Session AWS MCP Server Just Gave AI Agents Your Cloud Keys — Here's Why That Should Worry You Announcing the Trust Identity Protocol (TIP): HTTPS for the AI Era We built the feature in two days. Making it reliable took two weeks. LuisCore /for-agents.json — agent bootstrap — daily syndication · 2026-05-26 A Curious Journey Into Reverse Engineering an AI-Generated Python .exe Part 2: Enterprise Decision Intelligence Architecture: AI Governance, Threshold Policy Engines, and Operational AI Systems I will continue using Devise with Rails 8! The Developer's Guide to Picking the Right AI Code Model in 2026 (I Spent $500 So You Don’t Have To) 30 Kubernetes Tasks Every CKA Candidate Should Practice Before Exam Day Why Some Websites Feel Instantly Better to Use Advanced React Patterns I Wish I Knew 5 Years Ago ¿Cómo optimizar algoritmos en arreglos y listas con la técnica de dos punteros? I scanned 8 popular open source repos with one command. Here's what I found. mcp-probe v1.6.0: Stricter GitHub Actions checks for MCP CI gates How we connect two strangers' webcams fast (and keep the TURN bill small) LLM Agents Are Now Finding Zero-Days: How AI is Autonomously Rewriting the Rules of Vulnerability Research Minimal Code Doesn’t Mean Stable Code How I manage 40+ skills across Claude Code, Codex, and .agents folders Hardening Stealth Browser Fingerprint Integrity and State Persistence Quick Tip: Benchmarking Multimodal APIs in Under 10 Minutes How I Slashed My AI API Bill by 92% in 2026 — A Cost Optimizer's Speed Benchmark Guide How I Slashed My AI API Bill by 95% — A Practical Guide for 2026 A Go outbox library that runs inside your own DB transaction How I Built a Credit Optimizer That Saves 30-75% on AI Agent Costs (Open Architecture) The Missing POP: How I Ported a Yul Contract to Huff by Reading Every Opcode The Moment the Config Parser Became the Bottleneck Churn Tool Stack by Revenue Stage ($5K to $50K+) What I Learned Exploring AI-Generated 3D: A Hands-On Tour of Meshy, Tripo, and Three.js Day 15 - Software Composition Analysis(SCA) Contributing Upstream Instead of Forking: My grape-swagger-rails Story Behind The Badge: How We Built 2,000 Hackable Badges For Temporal Replay Access Control Doesn't Scale Linearly -- Part 3 33x faster than Rust: Why I stopped waiting for my compiler and built my own. I Built My First Production AWS Project as a Career Changer Why Detecting PII Matters More Than Ever JSON Schema in 10 Minutes — Validation, Types & Real Examples Python Tasks How I Started My Cybersecurity Journey as an SQA Engineer 🔐 Why "fancy fonts" in Discord and Instagram bios turn into boxes ☁️ GKE private cluster setup — common mistakes and how to avoid them I Thought a Username Didn’t Matter… Until I Saw How Much People Care About It Claude for Small Business: 382K Day-One Buyer's Guide I Built a Diagnostic Toolkit for PyTorch Because I Was Tired of Guessing Why Models Fail How I Built an AI-Powered Incident RCA Platform with LangGraph and RAG The Paywall Was a Painted Door Sonnet hallucinated. My agent stored it as fact. How React-Style Time-Slicing Keeps UIs Responsive 这个 Princeton 开源项目让 AI 自己修 Bug,19K Stars 但 90% 的人只用了 1% 功能 🔥 SWE-agent's 5 Hidden Uses Nobody Told You About 🔥 Decompiling Serial Number U-36: Python TERCOM Reconstruction, Cryptographic Logistical Forensics, and Swarm Consensus Fault Tolerance Microservices Patterns You Cannot Outrun a Wave I Fired My Entire Node.js Stack — Rust Rebuilt It in 3 Weeks (The Ugly Truth) BoxAgnts Introduction (2) — AI Agent Toolbox Cursor 3 ships parallel AI agents. Here is the multi-agent workflow that actually works. Prisma-7 A Complete Beginners Guide (With Free Cloud Database!) Akses HDD Rumah dari Laptop Kantor Pakai Tailscale + SMB (Tanpa VPN Ribet) Content Pipeline in MonoGame: Why I Don't Use It Debug Log #1 — The Pipeline That Looked Broken Data Structures in JavaScript: When to Use What (2026) BGP Route Flap Damping: A Solution or a New Problem? First look at AWS DevOps Agent The Next Big “Cult App” Probably Isn’t Another Social Media Platform From Template to Production-Shaped: An AI-Native Dev Flow for Go Side Projects Idempotency Keys: The API Pattern That Saves You From Duplicate Payments and Phantom Records Everyone's Building Jarvis. Nobody's Even Close. The Moment the Jaeger Tracer Exhausted Itself and What We Switched To How to Fix Tool-Use Loops in Autonomous Coding Agents Months of self-testing: Citations shine, other features remain unproven. Claude Code for Canary Deployments: How I Ship to 1% of Users Before Breaking Everything Your recurring scraper is re-downloading data that didn't change. Here's the 15-line fix (conditional GET) 20 Years of GPUs in Numbers: How FLOPS & TDP Grew, and Who Led the NVIDIA vs AMD Race (open dataset, 13.5k GPUs) Espressif Reveals CoreBoard and Korvo Dev Kits for ESP32-S31 Composable Abstraction Layer: o pattern que faltava entre Pinia e seus componentes Vue Your GitHub Actions Logs Are Leaking LLM Keys and Your SIEM Isn't Catching It Solving Complex Logic with Claude and Research Papers Building TheEpicBook: A Deep Dive into a Node.js Monolithic Web Application Haber yazilimi, haber scripti, haber sistemi: ayni urun, uc ayri arama niyeti Predicting Blood Glucose Fluctuations: Building a Transformer-based CGM Forecaster with PyTorch & InfluxDB Pre-task hooks: the one-line wire-up that gives your Hono agent shared memory Concurrent writes to a shared agent memory: what we shipped, what we punted on Building a Production Serverless URL Shortener on AWS — 21 Articles, Every Test Run for Real My CKA Cheat Sheet: Commands, Aliases, and Documentation Tricks I Used During the Exam Frontend Engineering Beyond Pixels: The Architecture of Digital Accessibility VLA or IL? A Controlled Dataset for Testing Whether Finetuning Turns Your VLA into a Fancy Imitation Learner Fabric AI Functions Turn GenAI Into a Data Pipeline Step Proximate vs Ultimate: The Bug Is Never Just the Bug The Treasure Hunt Engine That Broke Before the Traffic Did Reset Windows Update: The Definitive MSP Guide to RWU Your Resume Was Never Built for This AI Writes 46% of Code Now: What Snap's Layoffs Mean for Developers in 2026 From Chatbot to Agent — Tool Calling with NVIDIA NIM Fatigue and Fracture Mechanics: Why Parts Break Below Their Yield Strength I built a token-level debugger for comparing two LLMs VCP-Virtual Private Cloud Embedding sing-box in an iOS messenger to bypass Russian DPI (no VPN) Microsoft Copilot just exfiltrated a company's files. The attack was one email. Here's the mechanism. RAG 시스템 실전 구축 (v42)
HTML meta referrer: canonical reference
Joseph Anady · 2026-05-26 · via DEV Community

framework-html-meta-referrer.md

Comprehensive reference for HTML <meta name="referrer">, the page level referrer policy declaration. Covers the spelling history (HTTP header is Referer: due to historical misspelling; the policy directive uses correctly spelled Referrer-Policy; the HTML meta tag uses name="referrer"), the eight valid values (no-referrer, no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url), the modern browser default (strict-origin-when-cross-origin per 2020+ specifications), the privacy implications (Referer header reveals where users came from), the security implications (full URLs can leak session tokens, internal paths, query parameters), the relationship with the HTTP Referrer-Policy header (covered in framework-http-security-headers.md; HTTP header generally wins over meta tag), the analytics and affiliate marketing tradeoffs (many tools depend on referrer; stricter policies break them), the per element overrides (rel="noreferrer" on links, referrerpolicy attribute on links and images), and the Bubbles per client decision framework with explicit YMYL patterns for Arkansas Counseling and Wellness (mental health privacy) and Handled Tax and Advisory (financial privacy) plus the federal subcontractor pattern for WeCoverUSA and SDVOSB context. Built for Bubbles (Debian, Nginx 1.26+, FastAPI sidecar on port 9090, self hosted origin at 169.155.162.118, no Cloudflare or third party CDN in front).

This is the eleventh framework in the HTML signal track, following meta robots, charset, viewport, description, keywords, author, generator, copyright, theme-color, and color-scheme. Companion to the 12 wire layer frameworks especially framework-http-security-headers.md (the HTTP Referrer-Policy header is the canonical layer; the meta tag is the HTML supplement).

Audience: humans configuring privacy conscious referrer behavior on client sites, AI assistants generating HTML head sections with appropriate referrer policy, developers protecting session tokens from URL leakage to third party sites, healthcare and financial site operators (Arkansas Counseling, Handled Tax) maintaining client privacy, federal subcontractors balancing privacy with operational needs, marketers preserving affiliate tracking while limiting unnecessary leakage, and anyone troubleshooting "outbound links to competitors are leaking session info", "the affiliate program isn't tracking our referrals", "Google Analytics shows referrer dropped after we changed something", or "should we set this at HTTP level or HTML level".


TABLE OF CONTENTS

  1. Definition
  2. Why It Matters
  3. What This Covers
  4. The Referrer Mental Model (read this first)
  5. The Spelling History (Referer vs Referrer)
  6. The Eight Valid Values
  7. The Modern Browser Default (strict-origin-when-cross-origin)
  8. Privacy Implications
  9. Security Implications (URL Token Leakage)
  10. The HTTP Referrer-Policy Header Relationship
  11. Analytics And Affiliate Tradeoffs
  12. Per Link And Per Element Overrides
  13. The Bubbles Per Client Decision Framework
  14. The Federal Subcontractor Pattern (SDVOSB)
  15. The YMYL Privacy Pattern (Healthcare And Financial)
  16. Asset Class And Use Case Recipes
  17. Bubbles Standard Pattern (paste ready)
  18. Audit Checklist
  19. Common Pitfalls
  20. Diagnostic Commands
  21. Cross-References

1. DEFINITION

<meta name="referrer"> is the HTML directive declaring the page level referrer policy. It controls what information browsers include in the Referer: HTTP header when navigating from this page to other pages or loading subresources. Defined in the W3C Referrer Policy specification.

<head>
    <meta name="referrer" content="strict-origin-when-cross-origin">
</head>

Enter fullscreen mode Exit fullscreen mode

Three structural facts shape how the directive works:

  • It controls the Referer HTTP header value. When a user clicks a link, follows a redirect, or the browser loads an embedded resource, the browser sends a Referer: header indicating where the request came from. The referrer policy controls what value is sent (or whether to send anything).
  • The spelling is historical. The HTTP header is Referer: (one R, two E's), a misspelling that stuck since 1996. The policy directive and meta tag use correctly spelled Referrer / referrer.
  • It is one of two layers for setting policy. The HTTP Referrer-Policy response header is the authoritative layer (covered in framework-html-meta-referrer.md). The HTML meta tag is page level; the HTTP header is more granular. When both present, behavior depends on which loaded first (usually HTTP wins).

For Bubbles client sites in 2026, the convention is to set Referrer-Policy: strict-origin-when-cross-origin via HTTP header at the nginx layer (preferred), with the HTML meta tag as fallback for environments where HTTP headers cannot be controlled. For YMYL clients (Arkansas Counseling, Handled Tax) and federal subcontractor work (WeCoverUSA), the more restrictive same-origin or no-referrer may apply.


2. WHY IT MATTERS

Seven independent considerations push correct referrer policy from "ignored detail" to "actively managed signal" in 2025 and forward.

Full URLs in Referer headers leak sensitive information. When a user navigates from https://example.com/account/?session=abc123&token=xyz789 to another site, the destination receives the entire URL as Referer. Session tokens, query parameters, internal paths, and potentially confidential data flow to third parties. Restricting to origin only (https://example.com/) prevents this leakage.

Privacy regulations require minimum data sharing. GDPR, CCPA, and similar regulations require organizations to share only necessary data with third parties. Sending full URLs (containing paths users visited) to every external site is often more sharing than needed. Restricting referrer reduces compliance surface area.

Healthcare and financial sites have specific privacy obligations. HIPAA, FTC financial privacy rules, and similar regulations require protecting client information. Arkansas Counseling and Wellness Services (mental health) and Handled Tax and Advisory (financial) handle sensitive data; full URL referrer to third party analytics or external links is an unnecessary privacy risk.

Federal subcontractor work has security baselines. NIST 800-53 and CIS Benchmarks recommend information minimization in HTTP headers. SDVOSB federal subcontractors (Joseph's context) often face security audits that flag overly permissive referrer policies.

Analytics and affiliate marketing depend on referrer. Many tools rely on the Referer header:

  • Google Analytics (referrer source/medium attribution).
  • Affiliate networks (commission attribution).
  • Some advertising platforms. Restricting referrer too aggressively breaks these systems.

The 2020+ browser default changed. Until 2020, browsers defaulted to no-referrer-when-downgrade (send full URL on same-secure protocol; nothing on HTTPS to HTTP downgrade). The modern default is strict-origin-when-cross-origin (more privacy preserving). Sites that depended on full URL referrers may have broken silently.

The HTML meta tag vs HTTP header distinction matters. Setting it via HTTP header at nginx applies to all pages; setting via meta tag is per page. HTTP header is preferred for site wide policy; meta tag is useful for per page overrides or when HTTP cannot be controlled.

Cost of getting it wrong. Misconfigured referrer policy produces measurable privacy and operational damage. Real examples:

  • Bubbles client had session tokens in URL query parameters. The site had no referrer policy set; default was unsafe-url (in some legacy browsers). When users clicked external links, full URLs including session tokens went to third parties. One affected user's session was hijacked from token leakage in browser history of a public computer. Fix: set Referrer-Policy: strict-origin-when-cross-origin in nginx; refactor URLs to not include session tokens in query string.
  • Arkansas Counseling and Wellness Services site had no-referrer-when-downgrade (legacy default). Patients clicking external resource links sent the full URL of which appointment booking page they came from to external sites. This was minor but constituted unnecessary information sharing for a healthcare context. Fix: set strict-origin-when-cross-origin or same-origin.
  • Handled Tax (Amanda Emerdinger) had documentation pages with URLs like /tax-prep/amended-returns/. Without referrer policy, clicking external IRS links sent the user's previous page path to the IRS. While the IRS doesn't track this maliciously, it's unnecessary information sharing. Fix: strict-origin-when-cross-origin.
  • Real estate client had no-referrer set; affiliate tracking from Zillow inbound clicks broke (Zillow couldn't tell which listing brought traffic). Fix: relaxed to strict-origin-when-cross-origin (referrer source preserved for affiliate attribution).
  • Federal subcontractor site (WeCoverUSA) had no referrer policy. Security audit flagged this as information disclosure risk. Fix: set strict-origin-when-cross-origin plus same-origin for specific internal pages with sensitive paths.

All preventable with the rules below.


3. WHAT THIS COVERS

The meta referrer tag plus its full operational context:

  1. The spelling history: Referer vs Referrer; why the inconsistency.
  2. The eight valid values: from most permissive to most restrictive.
  3. The modern default: strict-origin-when-cross-origin behavior.
  4. The HTTP header vs meta tag relationship: which to use when.
  5. Privacy and security implications: URL leakage scenarios.
  6. Analytics and affiliate tradeoffs: not too strict, not too loose.
  7. Per element overrides: link and image specific policies.
  8. The Bubbles application: per client, with YMYL and federal patterns.

Section 13 is the Bubbles decision framework. Section 14 covers federal/SDVOSB patterns; Section 15 covers YMYL patterns.


4. THE REFERRER MENTAL MODEL (READ THIS FIRST)

The browser maintains a "referrer" representing the page that initiated the current navigation. When making outbound requests, this referrer is sent as the Referer: HTTP header.

User browses https://example.com/account/order-history/?session=abc123
   |
   v
User clicks a link to https://external-site.com/help/
   |
   v
==================== BROWSER DECISION ====================
   |
   |---> What referrer to send to external-site.com?
   |
   |---> Based on policy in effect:
        - HTTP Referrer-Policy header on example.com (preferred)
        - <meta name="referrer"> on the page (fallback)
        - Browser default (strict-origin-when-cross-origin in 2026)
   |
   v
==================== POLICY EFFECTS ====================
   |
   |---> no-referrer
   |     Referer header: (not sent)
   |
   |---> origin
   |     Referer: https://example.com/
   |
   |---> strict-origin-when-cross-origin (default)
   |     Cross-origin: Referer: https://example.com/
   |     Same-origin: Referer: https://example.com/account/order-history/?session=abc123
   |
   |---> unsafe-url
   |     Referer: https://example.com/account/order-history/?session=abc123
   |     (Full URL including session token sent to external-site.com)

==================== THE PROTECTION HIERARCHY ====================
   |
   v
For privacy: no-referrer (no information shared).
   |
For analytics: strict-origin-when-cross-origin (modern default; origin shared cross-site).
   |
For affiliate: strict-origin-when-cross-origin (origin sufficient for attribution).
   |
For paranoid: same-origin (no referrer to external sites at all).
   |
For maximum interop: no-referrer-when-downgrade (legacy default, full URL on same protocol).

Enter fullscreen mode Exit fullscreen mode

Six rules govern the system:

  1. Default to strict-origin-when-cross-origin (matches modern browser default; balances privacy and functionality).
  2. For YMYL or sensitive content: same-origin or no-referrer.
  3. For federal subcontracting: strict-origin-when-cross-origin minimum; consider same-origin for sensitive paths.
  4. Set via HTTP header preferred (covers all pages; more authoritative).
  5. HTML meta tag as fallback when HTTP cannot be controlled.
  6. Per element overrides for specific cases (analytics partner links may need different policy).

A correctly configured Bubbles client site has a sensible default policy set via HTTP header, optional HTML meta tag as supplement, and per element overrides for specific cases requiring different behavior.


5. THE SPELLING HISTORY (REFERER VS REFERRER)

The "Referer" misspelling is one of the most enduring artifacts of early web history.

5.1 The Original Misspelling

When the HTTP specification was written in 1996 (Phillip Hallam-Baker's contribution), the header for indicating the previous page was named "Referer". This is a misspelling of "Referrer" (the correct English word has two R's in the middle).

By the time anyone noticed, the misspelling had been canonized in implementations and could not be corrected without breaking compatibility.

5.2 The Current State

Context Spelling
HTTP request header Referer: (one R, misspelled)
HTTP response header for policy Referrer-Policy: (correct spelling)
HTML meta tag <meta name="referrer"> (correct spelling)
JavaScript document API document.referrer (correct spelling)
HTML link attribute referrerpolicy (correct spelling)
CSS specification language "referrer" (correct spelling)

The original request header keeps the misspelling. Everything written since uses the correct spelling.

5.3 The Practical Impact

Two consistent spelling rules:

  1. HTTP request header: always Referer: (one R).
  2. Everything else: Referrer (two R's).

Mistakes:

WRONG:
GET /page HTTP/1.1
Referrer: https://example.com/
(Servers ignore this; "Referer" is the only recognized header.)

WRONG:
<meta name="referer" content="...">
(Browsers ignore this; "referrer" is the only recognized meta name.)

Enter fullscreen mode Exit fullscreen mode

Test:

# Verify the meta tag name spelling
curl -s https://example.com/ | grep -oE 'meta name="(referer|referrer)" content="[^"]+"'

# Should be: meta name="referrer" content="..."
# If you see meta name="referer", that's WRONG; browsers ignore it

Enter fullscreen mode Exit fullscreen mode

5.4 The Mental Trick

  • HTTP header (the misspelled one): one R, like "ref-er-er".
  • Everything else: two R's, like "re-fer-rer".

For Bubbles: always use the correct spelling in HTML and HTTP response header configuration.


6. THE EIGHT VALID VALUES

The Referrer Policy specification defines eight values, ordered from most permissive to most restrictive.

6.1 unsafe-url

<meta name="referrer" content="unsafe-url">

Enter fullscreen mode Exit fullscreen mode

Always send the full URL, including path and query string, regardless of destination or protocol.

Behavior:

  • Same origin: full URL.
  • Cross origin same protocol: full URL.
  • HTTPS to HTTP downgrade: full URL (this is the "unsafe" part).

Use case: rarely. Legacy systems requiring full referrer for tracking.

Privacy: maximum leakage. Avoid.

6.2 origin

<meta name="referrer" content="origin">

Enter fullscreen mode Exit fullscreen mode

Send only the origin (scheme + host + port), never the path.

Behavior:

  • Same origin: just https://example.com/.
  • Cross origin: just https://example.com/.
  • Downgrade: just https://example.com/.

Use case: when you want destinations to know you exist but not which page they came from.

6.3 origin-when-cross-origin

<meta name="referrer" content="origin-when-cross-origin">

Enter fullscreen mode Exit fullscreen mode

Send full URL for same origin requests; origin only for cross origin.

Behavior:

  • Same origin: full URL.
  • Cross origin: just origin.
  • Downgrade: full URL or origin (depends on cross/same origin).

Use case: preserve internal path tracking; minimize external leakage.

6.4 same-origin

<meta name="referrer" content="same-origin">

Enter fullscreen mode Exit fullscreen mode

Send full URL for same origin; nothing for cross origin.

Behavior:

  • Same origin: full URL.
  • Cross origin: no referrer.
  • Downgrade: no referrer.

Use case: strict; prevents any information leaking to external sites.

6.5 strict-origin

<meta name="referrer" content="strict-origin">

Enter fullscreen mode Exit fullscreen mode

Send origin only; suppress on downgrade.

Behavior:

  • Same origin: just origin.
  • Cross origin same protocol: just origin.
  • HTTPS to HTTP downgrade: no referrer.

Use case: balances privacy with cross-site analytics; protects against downgrade.

6.6 strict-origin-when-cross-origin

<meta name="referrer" content="strict-origin-when-cross-origin">

Enter fullscreen mode Exit fullscreen mode

The modern default. Send full URL same origin; origin cross origin; suppress on downgrade.

Behavior:

  • Same origin: full URL.
  • Cross origin same protocol: just origin.
  • HTTPS to HTTP downgrade: no referrer.

Use case: the modern web default. Balances privacy, security, and analytics needs.

6.7 no-referrer-when-downgrade

<meta name="referrer" content="no-referrer-when-downgrade">

Enter fullscreen mode Exit fullscreen mode

The historical default. Send full URL except on HTTPS to HTTP downgrade.

Behavior:

  • Same origin: full URL.
  • Cross origin same protocol: full URL.
  • HTTPS to HTTP downgrade: no referrer.

Use case: legacy compatibility. Not recommended for new sites; modern browsers default to stricter behavior.

6.8 no-referrer

<meta name="referrer" content="no-referrer">

Enter fullscreen mode Exit fullscreen mode

Never send a Referer header.

Behavior:

  • All requests: no referrer at all.

Use case: maximum privacy. Affiliate marketing and analytics often break.

6.9 The Values Summary Table

Value Same origin Cross origin Downgrade
unsafe-url Full URL Full URL Full URL
no-referrer-when-downgrade Full URL Full URL None
origin Origin Origin Origin
origin-when-cross-origin Full URL Origin Full or Origin
same-origin Full URL None None
strict-origin Origin Origin None
strict-origin-when-cross-origin (modern default) Full URL Origin None
no-referrer None None None

6.10 The Bubbles Default Choice

For most Bubbles client sites: strict-origin-when-cross-origin.

This matches the modern browser default, balances privacy with functionality, and is the recommended starting point.


7. THE MODERN BROWSER DEFAULT (STRICT-ORIGIN-WHEN-CROSS-ORIGIN)

In 2020, Chrome 85 changed its default referrer policy from no-referrer-when-downgrade to strict-origin-when-cross-origin. Other major browsers followed.

7.1 The Change

Before (pre 2020):

Default: no-referrer-when-downgrade
Behavior: full URL on same protocol; nothing on downgrade.
Implication: external sites received your full URL (with path, query).

Enter fullscreen mode Exit fullscreen mode

After (2020+):

Default: strict-origin-when-cross-origin
Behavior: full URL same origin; origin only cross origin; nothing on downgrade.
Implication: external sites only see your origin (https://example.com/).

Enter fullscreen mode Exit fullscreen mode

7.2 What Changed In Practice

For sites that DID NOT set a policy:

  • Internal links: same as before; full URL.
  • Cross origin links: now only origin, not full URL.
  • HTTPS to HTTP: same as before; no referrer.

For sites with sensitive query parameters in URLs:

  • External link clicks: no longer leak full URLs.
  • Improvement in default privacy posture.

7.3 The Implication For Sites

  • Sites that need full URL referrer for analytics: may have broken silently in 2020.
  • Sites that didn't care: no observable change for most users.
  • Sites that DID set unsafe-url explicitly: still behave the same.

For Bubbles: the default change is generally positive. Sites without explicit policy now have better default privacy.

7.4 The Explicit Declaration Value

Setting strict-origin-when-cross-origin explicitly:

  • Matches modern default behavior.
  • Documents the intent (rather than relying on browser implicit behavior).
  • Survives potential future default changes.

Convention: explicitly declare strict-origin-when-cross-origin (or appropriate value per use case) rather than relying on implicit defaults.


8. PRIVACY IMPLICATIONS

Referrer policy directly affects user privacy.

8.1 What Referer Reveals

When a user clicks from page A to page B, page B's server receives:

  • The URL of page A (or origin only, depending on policy).
  • This is visible in the destination's server logs.
  • Used by analytics tools, affiliate networks, security systems.

For external sites: they learn where users came from.

8.2 The Path Privacy Concern

A URL like:

https://medical-site.com/conditions/depression/treatment-options/

Enter fullscreen mode Exit fullscreen mode

reveals:

  • User was researching depression.
  • User was looking for treatment.

Without referrer policy, this URL gets sent to every external site the user navigates to (Google Analytics on that destination, advertising scripts, etc.). The destination's operators learn what the user was viewing on your site.

For Arkansas Counseling and Wellness, this is a HIPAA adjacent concern (not strictly HIPAA since referer is browser behavior, not medical record, but the privacy intent is similar).

8.3 The Query Parameter Privacy Concern

URLs with query parameters:

https://example.com/account/?session=abc123&user=joseph

Enter fullscreen mode Exit fullscreen mode

Without referrer policy:

  • External sites receive the session token and username in their logs.
  • Browser developer tools, browser history, and any logging on the destination capture this.
  • Session hijacking risk; credential exposure.

8.4 The Fix

For YMYL clients (mental health, financial), the privacy fix:

<meta name="referrer" content="same-origin">
<!-- Cross origin requests get no referrer -->

Enter fullscreen mode Exit fullscreen mode

Or:

<meta name="referrer" content="no-referrer">
<!-- Maximum privacy; analytics may break -->

Enter fullscreen mode Exit fullscreen mode

For general sites:

<meta name="referrer" content="strict-origin-when-cross-origin">
<!-- Modern default; origin shared cross origin -->

Enter fullscreen mode Exit fullscreen mode

8.5 The Tradeoff With Affiliate

Affiliate tracking often depends on referrer. Stricter policies can break commission attribution.

For sites with affiliate programs (real estate clients with Zillow affiliate, for example):

  • strict-origin-when-cross-origin: origin sufficient for attribution.
  • same-origin or no-referrer: affiliate tracking broken.

Convention: use strict-origin-when-cross-origin to preserve affiliate functionality while protecting path level privacy.


9. SECURITY IMPLICATIONS (URL TOKEN LEAKAGE)

Referer header can leak sensitive information beyond privacy concerns.

9.1 The Session Token Pattern

Some sites include session tokens in URLs:

https://example.com/dashboard/?token=eyJhbGciOiJIUzI1NiJ9...

Enter fullscreen mode Exit fullscreen mode

Without strict referrer policy:

  • User clicks external link from dashboard.
  • External site receives full URL including token.
  • External site (or anyone with log access) can use the token to impersonate the user.

9.2 The Password Reset Token Pattern

Password reset emails often contain URLs:

https://example.com/reset-password/?token=abc123xyz&user=joseph

Enter fullscreen mode Exit fullscreen mode

When user clicks the link and the page renders, any external resources loaded:

  • Receive the full URL as referrer.
  • Token is leaked to third party CDNs, analytics, etc.

Fix:

  • Use one time tokens.
  • Set restrictive referrer on password reset pages specifically.
  • Move tokens to POST body or session cookies.

9.3 The Internal Path Disclosure

Internal paths can reveal architecture:

https://example.com/admin/users/123/profile/

Enter fullscreen mode Exit fullscreen mode

Without referrer policy, external sites learn:

  • /admin/ exists on the site.
  • User IDs are sequential (123).
  • Profile pages exist at this pattern.

This is information disclosure that aids attackers.

9.4 The Fix Strategy

Multi layer:

  1. Set restrictive referrer policy (HTTP header preferred).
  2. Don't put sensitive tokens in URLs (use POST body or cookies).
  3. Don't expose internal paths in URLs (use opaque identifiers).
  4. Use HTTPS exclusively (referrer is suppressed on downgrade by modern defaults).

9.5 The Bubbles Hardening

For every Bubbles client site, especially those with sensitive paths:

# /etc/nginx/sites-enabled/example.com.conf

server {
    listen 443 ssl http2;
    server_name example.com;

    # Referrer policy (HTTP header; preferred over meta tag)
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # ... other directives ...
}

Enter fullscreen mode Exit fullscreen mode

nginx -t && systemctl reload nginx

Enter fullscreen mode Exit fullscreen mode

Plus optionally on specific sensitive pages:

# /opt/bubbles/services/example.com/main.py
@app.get("/password-reset/")
async def password_reset(request: Request, response: Response):
    response.headers["Referrer-Policy"] = "no-referrer"
    return templates.TemplateResponse("password_reset.html", {
        "request": request,
    })

Enter fullscreen mode Exit fullscreen mode


10. THE HTTP REFERRER-POLICY HEADER RELATIONSHIP

The HTTP header vs HTML meta tag distinction.

10.1 The Two Layers

HTTP layer (preferred):

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

HTML meta tag layer:

<meta name="referrer" content="strict-origin-when-cross-origin">

Enter fullscreen mode Exit fullscreen mode

10.2 The Differences

Aspect HTTP header HTML meta tag
Scope All pages served by config Specific page
Authority Higher Lower
Timing Set before HTML parsing Set during HTML parsing
Coverage All responses (including 404s, redirects) HTML pages only
Granularity Per route via nginx location Per page
Browser support Universal Universal

10.3 When Both Are Set

If both HTTP header AND meta tag are present:

  • HTTP header typically wins (specs vary slightly).
  • Browser may use the more specific or stricter.

For consistency: align both to the same value.

10.4 The Preferred Pattern For Bubbles

Set via HTTP header at nginx (covers all pages including 404s):

# /etc/nginx/snippets/security-headers.conf
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
# ... etc

Enter fullscreen mode Exit fullscreen mode

# /etc/nginx/sites-enabled/example.com.conf
server {
    # ...
    include /etc/nginx/snippets/security-headers.conf;
    # ...
}

Enter fullscreen mode Exit fullscreen mode

nginx -t && systemctl reload nginx

Enter fullscreen mode Exit fullscreen mode

This sets the policy site wide.

For HTML meta tag as fallback (or override on specific pages):

<!-- Specific page needs different policy -->
<meta name="referrer" content="no-referrer">

Enter fullscreen mode Exit fullscreen mode

10.5 The Cross Reference

The HTTP Referrer-Policy header is the canonical reference in framework-http-security-headers.md. This HTML meta tag framework is the supplementary HTML layer.

For most Bubbles client work: configure at HTTP layer; rarely need the meta tag.

For specific pages with different needs: use meta tag for per page override.


11. ANALYTICS AND AFFILIATE TRADEOFFS

Stricter referrer policies break some external services that depend on referrer.

11.1 What Depends On Referrer

  • Google Analytics: referrer source/medium attribution.
  • Affiliate networks: commission attribution.
  • Some advertising platforms: click attribution.
  • Anti spam systems: referrer fingerprinting.
  • Some authentication systems: referrer based CSRF protection.

11.2 The Impact By Policy

Policy Analytics impact Affiliate impact
unsafe-url Full attribution Full attribution
no-referrer-when-downgrade Full attribution Full attribution
strict-origin-when-cross-origin Origin attribution only Origin attribution (usually sufficient)
same-origin Cross site analytics broken Affiliate broken
no-referrer All cross site tracking broken Affiliate broken

11.3 The Bubbles Balance

For most clients:

  • Goal: keep analytics and affiliate functional.
  • Recommendation: strict-origin-when-cross-origin (modern default).
  • Origin level attribution is usually sufficient:
    • Google Analytics shows "site: example.com" instead of specific page.
    • Affiliate networks attribute commission based on origin.
    • Most tools handle this gracefully.

11.4 The Strict Tradeoff

For YMYL or sensitive clients (Arkansas Counseling, Handled Tax):

  • Privacy takes priority over analytics granularity.
  • same-origin or no-referrer may be appropriate.
  • Loss of cross site analytics is acceptable for privacy compliance.

11.5 The Verification

# Test what referrer is sent
URL=https://example.com/

# Use curl to simulate request from URL
curl -sI "https://external-site.com/" -H "Referer: https://example.com/page/?session=abc"

# Examine logs on external destination (manual)
# Or use a controlled external endpoint to log received Referer

Enter fullscreen mode Exit fullscreen mode

For development: set up a test endpoint to log incoming Referer: headers and verify policy behavior.


12. PER LINK AND PER ELEMENT OVERRIDES

For specific elements that need different referrer behavior, use per element attributes.

12.1 The referrerpolicy Attribute

Can be applied to:

  • <a> (anchor links).
  • <area> (image maps).
  • <img> (images).
  • <iframe> (embedded frames).
  • <link> (resource links).
  • <script> (script tags).
<a href="https://external.com/" referrerpolicy="no-referrer">
    External link with no referrer
</a>

<img src="https://cdn.example.com/image.jpg" referrerpolicy="no-referrer">

<iframe src="https://embed.example.com/" referrerpolicy="strict-origin"></iframe>

Enter fullscreen mode Exit fullscreen mode

12.2 The rel="noreferrer" Attribute

The legacy method specifically for anchor links:

<a href="https://external.com/" rel="noreferrer">
    External link with no referrer (legacy syntax)
</a>

Enter fullscreen mode Exit fullscreen mode

The rel="noreferrer" is functionally equivalent to referrerpolicy="no-referrer" for anchor links. Both work; the new attribute is more general.

12.3 The rel="noreferrer noopener" Pattern

Common pattern for external links:

<a href="https://external.com/" target="_blank" rel="noreferrer noopener">
    External link in new tab
</a>

Enter fullscreen mode Exit fullscreen mode

  • target="_blank": open in new tab.
  • noreferrer: don't send referrer.
  • noopener: prevent the new tab from accessing window.opener of the originating page (security).

For external links opening in new tabs: include both noopener and noreferrer.

12.4 The Per Image Override

For images loaded from third party CDNs:

<img src="https://cdn.images.com/photo.jpg" referrerpolicy="no-referrer">

Enter fullscreen mode Exit fullscreen mode

Prevents the CDN from learning which page the image is embedded on (sometimes useful for privacy of internal pages).

12.5 The Per iframe Override

For embedded content:

<iframe src="https://embed.example.com/widget/" referrerpolicy="strict-origin"></iframe>

Enter fullscreen mode Exit fullscreen mode

The embedded site only learns the origin, not the specific page.

12.6 The Bubbles Application

For typical Bubbles client sites:

  • Default referrer policy at HTTP header level (strict-origin-when-cross-origin).
  • External links to competitors: rel="noreferrer noopener" (don't tell them you exist with referrer).
  • External links to partners: standard (preserve referrer for attribution).
  • Affiliate links: standard (preserve for attribution).
  • Sensitive pages (password reset, etc.): meta tag override to no-referrer.

13. THE BUBBLES PER CLIENT DECISION FRAMEWORK

Each client site needs a referrer policy decision.

13.1 The Decision Questions

  1. What is the site's privacy posture?

    • Standard: strict-origin-when-cross-origin.
    • YMYL: same-origin or stricter.
    • Federal: strict-origin-when-cross-origin minimum.
  2. Does the site depend on cross site analytics or affiliate?

    • Yes: strict-origin-when-cross-origin (preserves origin attribution).
    • No: stricter is acceptable.
  3. Are there sensitive paths or query parameters?

    • Yes: stricter policy, plus per page overrides.
    • No: standard policy sufficient.
  4. Federal subcontracting context?

    • Yes: align with NIST/CIS recommendations.
    • No: standard recommendations apply.

13.2 The Per Client Recommendations

ThatDeveloperGuy.com (Joseph's primary site):

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard policy; balanced for analytics and privacy.

TCB Fight Factory:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard policy.

Arkansas Counseling and Wellness Services (Dr. Kristy Burton):

add_header Referrer-Policy "same-origin" always;

Enter fullscreen mode Exit fullscreen mode

YMYL mental health; protect path information from external sites.

Handled Tax and Advisory (Amanda Emerdinger):

add_header Referrer-Policy "same-origin" always;

Enter fullscreen mode Exit fullscreen mode

YMYL financial; protect path information.

White River Cabins:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard travel/hospitality; balance with affiliate (booking referrer attribution).

Greenough's Guide Service:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard outdoor/recreation.

Local Living Real Estate (Laycee Maupin):

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard; preserves real estate affiliate attribution (Zillow, etc.).

Diana Undergust at Lake Homes Realty:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard; same reasoning as above.

WeCoverUSA (federal subcontractor):

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Plus stricter for sensitive routes:
location /restricted/ {
    add_header Referrer-Policy "same-origin" always;
}

Enter fullscreen mode Exit fullscreen mode

Federal baseline; stricter for sensitive paths.

Heritage Hardwood Floors NWA:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Enter fullscreen mode Exit fullscreen mode

Standard local business.

13.3 The Documentation Pattern

For each client project:

Referrer policy decision:
  Default: strict-origin-when-cross-origin
  Reasoning: standard balance for analytics and privacy
  Set via: HTTP header at nginx
  Specific page overrides: none

Or for YMYL:

Referrer policy decision:
  Default: same-origin
  Reasoning: YMYL mental health; protect path information
  Set via: HTTP header at nginx
  Specific page overrides: none

Enter fullscreen mode Exit fullscreen mode


14. THE FEDERAL SUBCONTRACTOR PATTERN (SDVOSB)

For Joseph's federal subcontracting work and the SDVOSB context, referrer policy aligns with security baselines.

14.1 The NIST 800-53 Connection

NIST 800-53 (the federal information system security baseline) includes controls about information disclosure. Specifically:

  • SC-8 (Transmission Confidentiality and Integrity): protect transmitted information.
  • SC-23 (Session Authenticity): protect session information.
  • AC-21 (Information Sharing): minimize unauthorized sharing.

Referrer policy is one mechanism for compliance with these controls.

14.2 The CIS Benchmark Recommendation

CIS Benchmarks (for various web servers and applications) recommend:

  • Setting Referrer-Policy header.
  • Recommended value: strict-origin-when-cross-origin or stricter.
  • Documenting the choice.

14.3 The Federal Pattern

For WeCoverUSA and other Joseph federal subcontracting:

# /etc/nginx/sites-enabled/wecoverusa.com.conf

server {
    listen 443 ssl http2;
    server_name wecoverusa.com;

    # Federal baseline: strict-origin-when-cross-origin minimum
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Sensitive paths: stricter policy
    location /federal-portal/ {
        add_header Referrer-Policy "same-origin" always;
    }

    location /agent-portal/ {
        add_header Referrer-Policy "no-referrer" always;
    }

    # ... rest of config ...
}

Enter fullscreen mode Exit fullscreen mode

14.4 The Audit Documentation

For federal subcontract documentation:

Referrer policy implementation:
  Standard pages: strict-origin-when-cross-origin
  Federal portal: same-origin
  Agent portal (sensitive): no-referrer

Rationale: protect path information for sensitive areas while
preserving analytics and operational functionality for standard pages.
Aligns with NIST 800-53 AC-21 and SC-8 controls.

Configured via: nginx HTTP response headers.
Verification: curl -sI <URL> | grep Referrer-Policy

Enter fullscreen mode Exit fullscreen mode

14.5 The Audit Verification

# Verify policy is set on all federal subcontractor sites
for url in https://wecoverusa.com/ https://wecoverusa.com/federal-portal/ https://wecoverusa.com/agent-portal/; do
    POLICY=$(curl -sI "$url" | grep -i "Referrer-Policy" | head -1 | tr -d '\r')
    echo "$url: $POLICY"
done

Enter fullscreen mode Exit fullscreen mode


15. THE YMYL PRIVACY PATTERN (HEALTHCARE AND FINANCIAL)

For YMYL clients with privacy obligations, stricter referrer policies are appropriate.

15.1 The Healthcare Pattern (Arkansas Counseling)

For Arkansas Counseling and Wellness Services:

add_header Referrer-Policy "same-origin" always;

Enter fullscreen mode Exit fullscreen mode

Reasoning:

  • Patient privacy is paramount.
  • External sites should not learn which counseling resource pages users visited.
  • Same origin policy: internal navigation preserves full URL; external links send no referrer.

Plus per page overrides for highly sensitive pages:

# /opt/bubbles/services/arcounselingandwellness.com/main.py

@app.get("/intake-form/")
async def intake_form(request: Request, response: Response):
    response.headers["Referrer-Policy"] = "no-referrer"
    # Maximum privacy on intake form
    return templates.TemplateResponse("intake.html", {"request": request})

@app.get("/conditions/{condition}/")
async def condition_page(condition: str, request: Request, response: Response):
    response.headers["Referrer-Policy"] = "no-referrer"
    # Maximum privacy on condition specific pages
    return templates.TemplateResponse("condition.html", {
        "request": request,
        "condition": condition,
    })

Enter fullscreen mode Exit fullscreen mode

15.2 The Financial Pattern (Handled Tax)

For Handled Tax and Advisory (Amanda Emerdinger):

add_header Referrer-Policy "same-origin" always;

Enter fullscreen mode Exit fullscreen mode

Reasoning:

  • Tax client privacy.
  • External sites should not learn what tax topics users explored.
  • Same origin keeps internal navigation functional.

Per page overrides for sensitive areas:

@app.get("/client-portal/")
async def client_portal(request: Request, response: Response):
    response.headers["Referrer-Policy"] = "no-referrer"
    return templates.TemplateResponse("portal.html", {"request": request})

Enter fullscreen mode Exit fullscreen mode

15.3 The Privacy Documentation

For YMYL clients, document the policy:

Privacy policy excerpt:
  We minimize information shared with third party sites.
  When users navigate from our site to external destinations,
  we only share our domain origin (e.g., "arcounselingandwellness.com")
  not the specific page visited. This protects information about
  what counseling resources you may have been researching.

Technical implementation:
  HTTP Referrer-Policy: same-origin
  Plus per page overrides for sensitive content.

Enter fullscreen mode Exit fullscreen mode

This privacy policy language can appear in the client's privacy policy page.

15.4 The Combined Approach

For Bubbles YMYL clients:

  1. Default policy: same-origin site wide.
  2. Per page overrides: no-referrer for highly sensitive pages.
  3. Privacy policy documentation: explains the approach.
  4. Annual review: as regulations evolve.

16. ASSET CLASS AND USE CASE RECIPES

Paste ready snippets per scenario.

16.1 Canonical Bubbles head (with meta tag fallback)

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="color-scheme" content="light dark">
    <meta name="referrer" content="strict-origin-when-cross-origin">

    <title>{{ title }}</title>
    <meta name="description" content="{{ description }}">

    <!-- ... -->
</head>

Enter fullscreen mode Exit fullscreen mode

The HTTP header is the canonical source; the meta tag is a fallback.

16.2 nginx HTTP header (preferred Bubbles configuration)

# /etc/nginx/sites-enabled/example.com.conf

server {
    listen 443 ssl http2;
    server_name example.com;

    # Modern default: strict-origin-when-cross-origin
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # ... rest of config ...
}

Enter fullscreen mode Exit fullscreen mode

nginx -t && systemctl reload nginx

# Verify
curl -sI https://example.com/ | grep -i "Referrer-Policy"
# Expected: referrer-policy: strict-origin-when-cross-origin

Enter fullscreen mode Exit fullscreen mode

16.3 YMYL pattern (healthcare or financial)

# Arkansas Counseling: same-origin
server {
    listen 443 ssl http2;
    server_name arcounselingandwellness.com;

    add_header Referrer-Policy "same-origin" always;

    # Sensitive paths: no-referrer
    location /intake/ {
        add_header Referrer-Policy "no-referrer" always;
    }

    location /conditions/ {
        add_header Referrer-Policy "no-referrer" always;
    }
}

Enter fullscreen mode Exit fullscreen mode

16.4 Federal subcontractor pattern

# WeCoverUSA
server {
    listen 443 ssl http2;
    server_name wecoverusa.com;

    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Federal portal: same-origin
    location /federal-portal/ {
        add_header Referrer-Policy "same-origin" always;
    }

    # Agent portal (sensitive): no-referrer
    location /agent-portal/ {
        add_header Referrer-Policy "no-referrer" always;
    }
}

Enter fullscreen mode Exit fullscreen mode

16.5 Per page override via meta tag

<!-- /opt/bubbles/services/example.com/templates/password_reset.html -->
<head>
    <meta charset="utf-8">
    <meta name="referrer" content="no-referrer">
    <!-- Override site default for this specific sensitive page -->
</head>

Enter fullscreen mode Exit fullscreen mode

16.6 Per link overrides

<!-- External link, no referrer -->
<a href="https://external.com/" rel="noreferrer noopener" target="_blank">
    Visit External Site
</a>

<!-- External link with per element policy -->
<a href="https://partner.com/" referrerpolicy="strict-origin">
    Partner Link
</a>

<!-- Image from external CDN with no referrer -->
<img src="https://cdn.images.com/photo.jpg" referrerpolicy="no-referrer" alt="Photo">

<!-- Iframe with strict origin -->
<iframe src="https://embed.example.com/widget/" referrerpolicy="strict-origin"></iframe>

Enter fullscreen mode Exit fullscreen mode

16.7 FastAPI per request policy

# Set referrer policy dynamically per request
from fastapi import FastAPI, Request, Response

app = FastAPI()

@app.middleware("http")
async def set_referrer_policy(request: Request, call_next):
    response = await call_next(request)

    # Standard pages: strict-origin-when-cross-origin
    policy = "strict-origin-when-cross-origin"

    # Override for sensitive paths
    if request.url.path.startswith("/intake/"):
        policy = "no-referrer"
    elif request.url.path.startswith("/conditions/"):
        policy = "no-referrer"
    elif request.url.path.startswith("/admin/"):
        policy = "same-origin"

    response.headers["Referrer-Policy"] = policy
    return response

Enter fullscreen mode Exit fullscreen mode

16.8 Outbound link audit

#!/bin/bash
# /usr/local/bin/external-links-audit.sh
# Check all outbound links for proper referrer protection

URL=$1

# Get all external links from page
EXTERNAL=$(curl -s "$URL" | grep -oE 'href="https?://[^"]+"' | sort -u | grep -v "$(curl -s "$URL" | grep -oE 'meta[^>]+name="og:url"[^>]+' | sed 's/.*content="\([^"]*\)".*/\1/' | sed 's/https\?:\/\/\([^/]*\).*/\1/')")

echo "External links on $URL:"
echo "$EXTERNAL"

# Check if they have noreferrer
for link in $EXTERNAL; do
    if curl -s "$URL" | grep -E "href=\"$link\"[^>]*rel=\"[^\"]*noreferrer" > /dev/null; then
        : # OK
    else
        echo "EXTERNAL WITHOUT noreferrer: $link"
    fi
done

Enter fullscreen mode Exit fullscreen mode

16.9 Bulk audit across all Bubbles client sites

#!/bin/bash
# /usr/local/bin/referrer-policy-audit.sh

echo "=== Referrer policy audit across Bubbles sites ==="

for site_dir in /var/www/sites/*/; do
    SITE=$(basename "$site_dir")

    # Get the URL from site directory naming
    URL="https://${SITE}"

    POLICY=$(curl -sI -L "$URL/" 2>/dev/null | grep -i "Referrer-Policy" | head -1 | tr -d '\r')

    if [ -z "$POLICY" ]; then
        echo "MISSING: $SITE - no Referrer-Policy header"
    else
        echo "$SITE: $POLICY"
    fi
done

Enter fullscreen mode Exit fullscreen mode

16.10 Verify policy enforcement

# Use a test endpoint to log incoming Referer headers
# (Could use webhook.site or a controlled FastAPI endpoint)

# /opt/bubbles/test-endpoints/referrer_logger.py
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/referrer-test")
async def log_referrer(request: Request):
    referer = request.headers.get("referer", "(none)")
    print(f"Received Referer: {referer}")
    return {"received_referrer": referer}

# Then visit your site, click a link to this endpoint, verify the Referer received

Enter fullscreen mode Exit fullscreen mode


17. BUBBLES STANDARD PATTERN (PASTE READY)

The canonical Bubbles referrer policy configuration.

17.1 The nginx Default

# /etc/nginx/snippets/security-headers.conf

# Referrer-Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Other security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# ... other from framework-http-security-headers.md

Enter fullscreen mode Exit fullscreen mode

# /etc/nginx/sites-enabled/example.com.conf
server {
    # ...
    include /etc/nginx/snippets/security-headers.conf;
    # ...
}

Enter fullscreen mode Exit fullscreen mode

17.2 The Per Client Configuration

# /opt/bubbles/services/example.com/client_config.py

CLIENT_REFERRER_POLICIES = {
    "thatdeveloperguy": {
        "default": "strict-origin-when-cross-origin",
        "overrides": {},
    },
    "tcb_fight_factory": {
        "default": "strict-origin-when-cross-origin",
        "overrides": {},
    },
    "arcounselingandwellness": {
        "default": "same-origin",
        "overrides": {
            "/intake/": "no-referrer",
            "/conditions/": "no-referrer",
        },
    },
    "handledtax": {
        "default": "same-origin",
        "overrides": {
            "/client-portal/": "no-referrer",
        },
    },
    "wecoverusa": {
        "default": "strict-origin-when-cross-origin",
        "overrides": {
            "/federal-portal/": "same-origin",
            "/agent-portal/": "no-referrer",
        },
    },
    # ... per client
}

Enter fullscreen mode Exit fullscreen mode

17.3 The HTML Fallback Template

{# /opt/bubbles/services/example.com/templates/base.html #}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Referrer policy fallback (HTTP header is canonical) -->
    {% if referrer_policy %}
    <meta name="referrer" content="{{ referrer_policy }}">
    {% endif %}

    <!-- Other meta tags -->
    <title>{{ title }}</title>
    <meta name="description" content="{{ description }}">

    {% block head_extra %}{% endblock %}
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

17.4 The Audit Workflow

# Weekly across all sites
referrer-policy-audit.sh

# After nginx config changes
nginx -t && systemctl reload nginx

# Verify on sample URLs
curl -sI https://example.com/ | grep -i "Referrer-Policy"
curl -sI https://example.com/intake/ | grep -i "Referrer-Policy"

Enter fullscreen mode Exit fullscreen mode

17.5 The Client Documentation Template

For each client project file:

Referrer Policy Configuration:

Default policy: strict-origin-when-cross-origin
Reasoning: standard balance for analytics and privacy

Per route overrides:
  /intake/: no-referrer (sensitive)
  /conditions/: no-referrer (sensitive)

Set via: HTTP response header in nginx
Verification: curl -sI <URL> | grep Referrer-Policy

Alignment with HTTP security headers: see framework-http-security-headers.md.

Enter fullscreen mode Exit fullscreen mode


18. AUDIT CHECKLIST

Run through these 40 items for production deployment.

Core policy

  1. [ ] HTTP Referrer-Policy header set in nginx for all sites.
  2. [ ] Default value is strict-origin-when-cross-origin (or more restrictive per client).
  3. [ ] Policy applies to all responses (always keyword in nginx).
  4. [ ] Verified via curl -sI on multiple URLs.

Per route overrides

  1. [ ] Sensitive routes (intake, password reset, admin) have stricter policies.
  2. [ ] YMYL clients have same-origin minimum at default.
  3. [ ] Federal portal routes have appropriate stricter policy.

HTML meta tag

  1. [ ] Meta tag included as fallback for environments without HTTP header control.
  2. [ ] Meta tag value matches HTTP header (consistency).
  3. [ ] Meta tag uses correctly spelled "referrer" (not "referer").

YMYL specific

  1. [ ] Arkansas Counseling and Wellness: same-origin policy.
  2. [ ] Handled Tax: same-origin policy.
  3. [ ] Per page overrides for highly sensitive content.

Federal subcontractor

  1. [ ] WeCoverUSA: strict-origin-when-cross-origin baseline.
  2. [ ] Sensitive federal routes: stricter (same-origin or no-referrer).
  3. [ ] Aligns with NIST 800-53 information disclosure controls.

Per link / element

  1. [ ] External links use rel="noreferrer noopener" where appropriate.
  2. [ ] External CDN images use referrerpolicy="no-referrer" where appropriate.
  3. [ ] Iframes have appropriate referrerpolicy attribute.

Analytics and affiliate

  1. [ ] Affiliate functionality verified working (origin attribution sufficient).
  2. [ ] Google Analytics receiving expected data.
  3. [ ] No broken cross site tracking that should work.

Privacy compliance

  1. [ ] Privacy policy documents referrer behavior.
  2. [ ] HIPAA/financial privacy alignment for YMYL clients.
  3. [ ] GDPR data sharing minimization.

Header coordination

  1. [ ] HTTP header takes precedence over meta tag (verified).
  2. [ ] All Bubbles security headers consistently set (snippets/security-headers.conf).

Documentation

  1. [ ] Per client referrer policy documented.
  2. [ ] Rationale for policy choice documented.
  3. [ ] Override routes documented.

Verification

  1. [ ] Test endpoint logs verify expected Referer values.
  2. [ ] Browser DevTools network tab shows expected headers.
  3. [ ] referrer-policy-audit.sh shows all sites configured.

Mistake checking

  1. [ ] No unsafe-url policy on production sites.
  2. [ ] No no-referrer-when-downgrade (legacy; use modern default).
  3. [ ] Spelling correct in meta tags ("referrer" not "referer").

Cross cutting

  1. [ ] Login pages have appropriate referrer policy.
  2. [ ] Password reset pages have no-referrer policy.
  3. [ ] API endpoints have appropriate policy.

After deployment

  1. [ ] Post deploy verification via curl -sI confirms all expected policies.

A site that passes all 40 has correctly configured referrer policy across all routes with appropriate privacy levels per client context.


19. COMMON PITFALLS

Fifteen patterns to recognize and avoid.

Pitfall 1: Misspelled meta name as "referer".
Symptom: <meta name="referer" content="..."> ignored by browsers.
Why it breaks: meta tag name must be "referrer" (two R's).
Fix: change to <meta name="referrer" content="...">.

Pitfall 2: No policy set; default unsafe-url behavior in old browsers.
Symptom: full URLs sent to external sites including sensitive query parameters.
Why it breaks: no explicit policy; legacy browsers may default permissively.
Fix: set explicit policy (modern default strict-origin-when-cross-origin).

Pitfall 3: unsafe-url set explicitly.
Symptom: full URLs sent to all destinations.
Why it breaks: maximum privacy leakage.
Fix: change to strict-origin-when-cross-origin or stricter.

Pitfall 4: no-referrer everywhere breaks affiliate.
Symptom: affiliate program shows zero attribution.
Why it breaks: too strict; affiliate networks need referrer.
Fix: relax to strict-origin-when-cross-origin (origin sufficient for affiliate).

Pitfall 5: YMYL site has standard policy.
Symptom: Arkansas Counseling site sends path information to external sites.
Why it breaks: insufficient privacy for healthcare context.
Fix: tighten to same-origin.

Pitfall 6: Session tokens in URL leaked via referrer.
Symptom: external site logs show URLs containing session tokens.
Why it breaks: tokens in URLs combined with permissive referrer.
Fix: stricter referrer plus move tokens out of URLs.

Pitfall 7: External links missing noreferrer noopener.
Symptom: clicking external links exposes window.opener; potential security issue.
Why it breaks: target="_blank" without noopener has security implications.
Fix: always use rel="noreferrer noopener" for external target="_blank" links.

Pitfall 8: HTML meta tag conflicts with HTTP header.
Symptom: page sets <meta name="referrer" content="no-referrer"> but HTTP header says strict-origin-when-cross-origin.
Why it breaks: usually HTTP wins; meta tag ignored.
Fix: align both, or remove meta tag if HTTP header is set.

Pitfall 9: Federal site without policy.
Symptom: WeCoverUSA security audit flag.
Why it breaks: NIST 800-53 controls reference referrer policy.
Fix: set policy and document.

Pitfall 10: Policy lost on redirects.
Symptom: redirects don't include the Referrer-Policy header.
Why it breaks: add_header in nginx may not apply to redirect responses without always keyword.
Fix: ensure always keyword in nginx directive.

Pitfall 11: Policy set per location but not globally.
Symptom: most pages have policy; 404 pages don't.
Why it breaks: location specific add_header; not inherited to default 404.
Fix: put add_header in server block, not location block. Or use snippets/include.

Pitfall 12: WordPress site has no referrer policy.
Symptom: WordPress site exposes referrer everywhere.
Why it breaks: WordPress doesn't set Referrer-Policy by default.
Fix: add to .htaccess or use security plugin.

Pitfall 13: Strict policy breaks legitimate cross site tracking.
Symptom: business intelligence dashboard shows referrer dropoff after policy change.
Why it breaks: same-origin or no-referrer blocks cross site analytics.
Fix: review what tracking is needed; choose appropriate policy.

Pitfall 14: Mixing legacy rel="noreferrer" and new referrerpolicy attribute.
Symptom: link has both attributes with conflicting values.
Why it breaks: behavior may vary by browser.
Fix: choose one approach per link.

Pitfall 15: Forgetting policy on password reset emails.
Symptom: password reset link page sends full URL referrer to embedded resources.
Why it breaks: reset tokens leak via referrer.
Fix: set no-referrer on password reset pages specifically; use POST for reset action.


20. DIAGNOSTIC COMMANDS

Reference of commands useful for referrer policy investigation.

Inspect HTTP header

# Check Referrer-Policy header
curl -sI https://example.com/ | grep -i "Referrer-Policy"

# Per route check
curl -sI https://example.com/intake/ | grep -i "Referrer-Policy"

# Verify "always" keyword effect (redirect should also have header)
curl -sIL https://example.com/redirect-source/ | grep -i "Referrer-Policy"

Enter fullscreen mode Exit fullscreen mode

Inspect meta tag

# Check meta tag
curl -s https://example.com/ | grep -oE 'meta name="referrer" content="[^"]+"'

# Also check for misspelled version (should be absent)
curl -s https://example.com/ | grep -c 'meta name="referer"'
# Expected: 0

Enter fullscreen mode Exit fullscreen mode

Cross check both layers

URL=$1

HTTP_POLICY=$(curl -sI "$URL" | grep -i "Referrer-Policy" | head -1 | tr -d '\r')
META_POLICY=$(curl -s "$URL" | grep -oE 'meta name="referrer" content="[^"]+"' | head -1)

echo "URL: $URL"
echo "HTTP header: $HTTP_POLICY"
echo "Meta tag: $META_POLICY"

if [ -n "$HTTP_POLICY" ] && [ -n "$META_POLICY" ]; then
    HTTP_VALUE=$(echo "$HTTP_POLICY" | sed 's/.*: *//')
    META_VALUE=$(echo "$META_POLICY" | sed 's/.*content="\([^"]*\)".*/\1/')

    if [ "$HTTP_VALUE" = "$META_VALUE" ]; then
        echo "ALIGNED: same value in both layers"
    else
        echo "MISMATCH: HTTP says '$HTTP_VALUE', meta says '$META_VALUE'"
    fi
fi

Enter fullscreen mode Exit fullscreen mode

Bulk audit across all sites

referrer-policy-audit.sh

Enter fullscreen mode Exit fullscreen mode

Test what referrer is sent

For development testing, set up a logging endpoint:

# /opt/bubbles/test-endpoints/referrer-logger.py
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/log-referrer")
async def log_referrer(request: Request):
    referer = request.headers.get("referer", "(none)")
    return {
        "received_referer": referer,
        "your_origin": request.headers.get("origin", "(none)"),
    }

Enter fullscreen mode Exit fullscreen mode

Run on port 9999:

uvicorn referrer-logger:app --port 9999

Enter fullscreen mode Exit fullscreen mode

Then click link from your site to http://localhost:9999/log-referrer; verify the response shows expected Referer value.

Check outbound links

# Find external links on a page
curl -s https://example.com/ | grep -oE 'href="https?://[^"]+"' | grep -v "example.com" | sort -u

Enter fullscreen mode Exit fullscreen mode

Verify nginx configuration

nginx -t

# Or show effective config for a site
nginx -T 2>/dev/null | grep -A 20 "server_name example.com"

Enter fullscreen mode Exit fullscreen mode

After configuration changes

nginx -t && systemctl reload nginx

# Verify
curl -sI https://example.com/ | grep -i "Referrer-Policy"

Enter fullscreen mode Exit fullscreen mode

Browser DevTools

In Chrome DevTools:

  1. Open the page.
  2. Open Network tab.
  3. Click an outbound link.
  4. In the request to the destination, examine Referer: header value.
  5. Verify it matches expected policy behavior.

21. CROSS-REFERENCES


APPENDIX A: ONE PAGE QUICK REFERENCE

For the person who just wants the answer.

The Bubbles rule

Set Referrer-Policy: strict-origin-when-cross-origin via nginx HTTP header on every site. YMYL clients get same-origin.

The canonical patterns

# Standard
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# YMYL (healthcare, financial)
add_header Referrer-Policy "same-origin" always;

# Federal subcontractor (with per route)
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location /federal-portal/ {
    add_header Referrer-Policy "same-origin" always;
}

Enter fullscreen mode Exit fullscreen mode

The HTML fallback

<meta name="referrer" content="strict-origin-when-cross-origin">

Enter fullscreen mode Exit fullscreen mode

The spelling rule

  • HTTP request header: Referer: (one R, misspelled historically).
  • Everything else: Referrer (two R's, correct spelling).

Five rules to memorize

  1. Default: strict-origin-when-cross-origin (matches modern browser default).
  2. YMYL: same-origin (Arkansas Counseling, Handled Tax).
  3. Federal: strict-origin-when-cross-origin minimum; stricter per route.
  4. HTTP header preferred over meta tag.
  5. External target="_blank" links: rel="noreferrer noopener".

Five commands every operator should know

# 1. Check policy
curl -sI URL | grep -i "Referrer-Policy"

# 2. Verify meta tag spelling (should be "referrer" not "referer")
curl -s URL | grep -E 'meta name="(referer|referrer)"'

# 3. Audit all Bubbles sites
referrer-policy-audit.sh

# 4. Test what referrer is sent (with test endpoint)
# Click external link; check destination logs

# 5. Apply changes
nginx -t && systemctl reload nginx

Enter fullscreen mode Exit fullscreen mode

Three end to end tests

# 1. HTTP header set
URL=https://example.com/
POLICY=$(curl -sI "$URL" | grep -i "Referrer-Policy" | head -1)
[ -n "$POLICY" ] && echo "OK: $POLICY" || echo "FAIL: no policy"

# 2. Spelling correct in meta tag
WRONG=$(curl -s "$URL" | grep -c 'meta name="referer"')
[ "$WRONG" = "0" ] && echo "OK: spelling correct" || echo "FAIL: misspelled"

# 3. Per route overrides work for YMYL clients
SENSITIVE_POLICY=$(curl -sI "$URL/intake/" | grep -i "Referrer-Policy")
echo "Intake route policy: $SENSITIVE_POLICY"

Enter fullscreen mode Exit fullscreen mode

If all three pass AND curl -sI consistently shows expected Referrer-Policy header across all routes AND verification endpoint receives expected Referer values, the referrer layer is correctly wired.


End of framework-html-meta-referrer.md.