server: avoid forwarding auth headers in CORS proxy#24373
Conversation
|
Real footgun worth studying since the proxy silently forwards the server API key and cookies to the target, but this breaks the explicit x-proxy-header-* passthrough for authenticated MCP servers, I think an allowlist forwarding only prefixed headers would solve it by construction, also please fill the PR template. @ngxson WDYT (the idea is there, not the current implementation) ? |
hmm that's unexpected, I think that worth fixing than the current PR (do not forward these headers to server, maybe only whitelist safe headers like user-agent). can you push a fix @ServeurpersoCom ? I'm not quite comfortable with the blacklist instead of whitelist approach in this PR, and on top of that, breaking edit: I can't think of any headers that need to be whitelisted; the user-agent can already be set explicitly via web ui, so probably just don't whitelist anything and only accept |
| auto new_key = key; | ||
| if (string_starts_with(new_key, "x-proxy-header-")) { | ||
| string_replace_all(new_key, "x-proxy-header-", ""); |
There was a problem hiding this comment.
should simply ignore all headers not starting with x-proxy-header-
frontend may need to be adapted too
|
Yes, if needed I will make a targeted PR that supersedes, the most important thing is to generate traces with a server (like my mcp.js) to really see what is leaking and what the PR solves. |
af76f7d to
e044c61
Compare
|
Updated, thanks for the review. The proxy now ignores all incoming headers that do not start with I also updated the regression test to cover both cases:
AI usage disclosure: I used OpenAI Codex to help identify the issue, prepare the patch, and update it after review. |
|
e044c61 to
ff26794
Compare
|
Thanks, updated. I changed the backend to only forward explicit |
| for (const [key, value] of new Headers(headers).entries()) { | ||
| const proxiedKey = | ||
| useProxy && !key.toLowerCase().startsWith('x-proxy-header-') | ||
| ? `x-proxy-header-${key}` |
There was a problem hiding this comment.
let's use a constant instead of magic string for the header namespace
There was a problem hiding this comment.
Done, I added a shared CORS_PROXY_HEADER_PREFIX constant and reused it in the proxy header builder, diagnostic fetch path, and header redaction logic.
ff26794 to
47e8892
Compare
| import { base } from '$app/paths'; | ||
| import { CORS_PROXY_ENDPOINT, CORS_PROXY_URL_PARAM } from '$lib/constants'; | ||
|
|
||
| export const CORS_PROXY_HEADER_PREFIX = 'x-proxy-header-'; |
There was a problem hiding this comment.
maybe let's rename it
| export const CORS_PROXY_HEADER_PREFIX = 'x-proxy-header-'; | |
| export const CORS_PROXY_HEADER_PREFIX = 'x-llama-server-proxy-header-'; |
| 'x-proxy-header-authorization': 'Bearer secret', | ||
| 'x-proxy-header-mcp-session-id': 'session-12345', | ||
| 'x-proxy-header-x-vendor-key': 'vendor-secret' | ||
| }); | ||
| const partial = new Map([['mcp-session-id', 5]]); | ||
| const result = sanitizeHeaders(headers, ['x-vendor-key'], partial); | ||
|
|
||
| expect(result['x-proxy-header-authorization']).toBe('[redacted]'); | ||
| expect(result['x-proxy-header-mcp-session-id']).toBe('....12345'); | ||
| expect(result['x-proxy-header-x-vendor-key']).toBe('[redacted]'); |
There was a problem hiding this comment.
and maybe let's use the constant here for this test, might be easier to update in the future
There was a problem hiding this comment.
Done, renamed the proxy header namespace to x-llama-server-proxy-header- across the backend and frontend, and updated the UI tests to build proxied header names from CORS_PROXY_HEADER_PREFIX.
47e8892 to
4ae0646
Compare
Overview
The CORS proxy now ignores incoming request headers by default and only forwards headers that are explicitly provided with the
x-proxy-header-*prefix. This prevents llama-server auth and cookie headers from being forwarded to the proxied target, while preserving explicit target-header passthrough for MCP servers that need authentication.Additional information
Frontend check: configured MCP headers already go through
buildProxiedHeaders(...). I also updated the MCP diagnostic fetch path so headers added dynamically by the MCP SDK during requests are wrapped asx-proxy-header-*whenuseProxyis enabled. Diagnostic header redaction now treats proxied headers as their underlying target headers, so proxied auth/session/custom header values are not logged in clear text.Tests / verification:
x-proxy-header-authorization.git diff --checkpasses locally.build/bin/Release/llama-server.exeis not present in this checkout.npm cifailed on this machine withENOSPCwhile installing dependencies.Requirements