MCP Server Security · Referrer Policy
MCP server Referrer-Policy security — preventing URL parameter leakage in outbound tool requests, strict-origin vs no-referrer trade-offs
When an MCP tool handler makes an outbound HTTP request, the browser or Node.js HTTP client attaches a Referer header containing the URL of the page that triggered the request. If that URL contains session tokens in query parameters (?token=abc123), user identifiers in the path (/users/42/sessions), or internal routing state, these values are sent in plaintext to the third-party server your tool called. The Referrer-Policy header (and the referrerPolicy fetch option) controls what gets sent — and the browser default sends more than most developers realize.
What the browser default policy actually sends
The browser default Referrer-Policy is strict-origin-when-cross-origin. This means:
- Same-origin requests: the full URL including path and query string is sent
- Cross-origin requests over HTTPS → HTTPS: only the origin (scheme + host + port) is sent, no path or query
- Cross-origin requests over HTTPS → HTTP (downgrade): the Referer header is omitted entirely
The cross-origin case looks safe, but the same-origin case leaks the full URL — including any query parameters — to every same-origin subresource. For a browser-based MCP client UI where the client URL is https://app.example.com/sessions/42?auth=token123, every same-origin API request in a tool handler sends Referer: https://app.example.com/sessions/42?auth=token123 to the server.
Server-side MCP tool handlers are different. In a Node.js MCP server, fetch() uses the Node.js undici client, not a browser. By default, undici does not send a Referer header unless you explicitly set one. The leakage risk here is not Referer from Node.js — it's the Origin and Referer headers that a browser-based MCP client UI sends when making cross-origin fetch calls to external APIs through the user's browser.
Referrer-Policy values: reference table
| Policy | Same-origin request | Cross-origin (HTTPS→HTTPS) | Cross-origin (HTTPS→HTTP) |
|---|---|---|---|
no-referrer | Nothing | Nothing | Nothing |
no-referrer-when-downgrade | Full URL | Full URL | Nothing |
origin | Origin only | Origin only | Origin only |
origin-when-cross-origin | Full URL | Origin only | Origin only |
same-origin | Full URL | Nothing | Nothing |
strict-origin | Origin only | Origin only | Nothing |
strict-origin-when-cross-origin | Full URL | Origin only | Nothing |
unsafe-url | Full URL | Full URL | Full URL |
Choosing the right policy for MCP server admin UIs
For MCP server admin UIs that load analytics, CDN assets, or call third-party APIs directly from the browser, use strict-origin as the page-level default:
<!-- In the <head> of every admin UI page --> <meta name="referrer" content="strict-origin"> <!-- Or set via HTTP header for stronger coverage (headers take precedence) --> # Caddy header Referrer-Policy "strict-origin"
strict-origin sends only the origin for all requests (same-origin and cross-origin), and sends nothing on HTTPS→HTTP downgrades. The full URL — with any tokens in path segments or query parameters — never leaves your origin in the Referer header.
Per-request override in fetch() and img tags
For MCP tool handlers that make fetch requests from a browser-based client, override the policy per-request to be maximally restrictive:
// Browser-side MCP tool handler making outbound request
const result = await fetch('https://api.external-service.com/data', {
method: 'GET',
referrerPolicy: 'no-referrer', // suppress Referer entirely for this request
credentials: 'omit', // don't send cookies to third-party
});
// For image resources loaded by tool output rendering
const img = document.createElement('img');
img.referrerPolicy = 'no-referrer'; // don't reveal current URL to image origin
img.src = toolOutput.imageUrl;
document.body.appendChild(img);
When to use no-referrer vs strict-origin
- Use
no-referrerfor tool output fetch requests to external APIs — the external server does not need to know your app's URL, and sending even the origin can reveal that users of your MCP client are visiting the external API (analytics leak). - Use
strict-originas the page-level default — it provides analytics continuity (same-origin analytics scripts still see the Referer origin) while blocking path and query leakage to cross-origin destinations. - Avoid
origin-when-cross-origin— it sends the full URL for same-origin requests, which leaks tokens in URL parameters to your own backend logs (a lower risk than third-party leakage, but unnecessary).
Don't put secrets in URL parameters. Referrer-Policy is damage control, not the primary fix. Session tokens, API keys, and authentication credentials should not appear in URL paths or query parameters. Use Authorization headers or POST body instead. Referrer-Policy prevents leakage of accidentally-present parameters but doesn't eliminate the root cause.
Server-side MCP tool handlers: Referer header injection risks
When a Node.js MCP server tool handler makes a fetch to an external API, Node's undici does not automatically send a Referer header. The risk runs in the opposite direction: an attacker who can control tool arguments might inject a Referer header to spoof the server's identity to the external API. Prevent this by stripping any user-supplied headers that include Referer before forwarding:
const BLOCKED_HEADERS = new Set(['referer', 'referrer', 'origin', 'cookie', 'authorization']);
function sanitizeUserHeaders(headers) {
const safe = {};
for (const [key, value] of Object.entries(headers ?? {})) {
if (!BLOCKED_HEADERS.has(key.toLowerCase())) {
safe[key] = value;
}
}
return safe;
}
server.tool('fetchWithHeaders', { url: z.string(), headers: z.record(z.string()).optional() }, async ({ url, headers }) => {
await safeResolveUrl(url); // SSRF check
const response = await safeFetch(url, {
headers: sanitizeUserHeaders(headers), // strip Referer, Origin, Cookie
});
return { content: [{ type: 'text', text: await response.text() }] };
});
SkillAudit findings
unsafe-url Referrer-Policy — full URL including query parameters sent to every cross-origin endpoint, including HTTP destinations; session tokens in URL parameters leak to external serversstrict-origin-when-cross-origin) sends full URL for same-origin requests; analytics scripts and same-origin API calls receive session tokens in path/query?token=, ?api_key=) — leaked to any resource loaded on that page regardless of Referrer-Policy policy (server logs, CDN access logs, analytics)Referer or Origin headers to external APIs — allows attacker to spoof the referring origin for external service authenticationno-referrer-when-downgrade policy on admin UI — sends full URL to all same-origin and cross-origin HTTPS destinations; tokens in URL parameters leak to analytics and API backendsSee also: Content Security Policy · CORS preflight security · SSRF advanced patterns
Audit your MCP server for Referrer-Policy gaps
SkillAudit checks for missing or permissive Referrer-Policy headers, tokens in URL parameters, and user-controlled Referer header forwarding.
Run free audit →