fix(daemon): treat Sec-Fetch-Site as a hint, not an authorization signal - #7081
fix(daemon): treat Sec-Fetch-Site as a hint, not an authorization signal#7081mrzhangkris wants to merge 1 commit into
Conversation
Non-browser HTTP clients can forge Sec-Fetch-Site trivially, so a no-Origin request carrying 'Sec-Fetch-Site: same-origin' must not widen the host check to the full OD_ALLOWED_ORIGINS allow-list on the non-loopback path. Only a loopback/private-LAN host (or an explicitly configured IP-literal origin) may omit the Origin header; reverse-proxy deployments with a hostname in OD_ALLOWED_ORIGINS must send Origin or use bearer auth instead. Fixes nexu-io#7041
|
Thanks @mrzhangkris — this is a clear security-hardening direction, and the red→green bug repro in the body makes the intent easy to follow. One small PR-body ask before review routing: could you add a short |
PerishCode
left a comment
There was a problem hiding this comment.
@mrzhangkris This cleanly removes the forgeable Sec-Fetch-Site authorization path while preserving the existing loopback/private-LAN and explicit-Origin behavior. I reviewed both changed ranges, the surrounding daemon authorization flow, the linked security issue, and the focused red-to-green regression coverage; the relevant daemon CI shard is passing. Nice focused hardening fix—thank you for making the trust boundary and deployment impact explicit.
Fixes #7041
Why
I hit this while auditing the daemon's local origin guard. The pain:
Sec-Fetch-Siteis set by user agents and JavaScript cannot modify it, but any non-browser HTTP client (curl, scripts) can forge it trivially. The current code treatsSec-Fetch-Site: same-originas sufficient authorization for a no-Origin request, widening the host check to the fullOD_ALLOWED_ORIGINSallow-list on the non-loopback path — so a forged header reaches guarded endpoints (/api/app-config, MCP oauth/install routes,/api/dir-exists, …) that should require a real browser same-origin context or bearer auth.What users will see
No UI change. Security behavior: a no-Origin request whose Host only matches a hostname entry in
OD_ALLOWED_ORIGINSis now rejected even when it carriesSec-Fetch-Site: same-origin. Reverse-proxy deployments that rely on that combination must send anOriginheader that matches the allow-list (or use bearer auth) — this is the fail-closed direction already confirmed by the maintainer in #7041.Surface area
OD_ALLOWED_ORIGINSare now rejected unless they carry a matchingOrigin;Sec-Fetch-Siteno longer substitutes.Screenshots
N/A (security guard change, no UI surface).
Bug fix verification
apps/daemon/tests/origin-validation.test.ts→isLocalSameOrigin: Sec-Fetch-Site is not an authorization signal (issue #7041)→ "rejects a no-Origin request even when Host matches OD_ALLOWED_ORIGINS and Sec-Fetch-Site is same-origin (forged header cannot authorize)".mainand green on this branch? Yes. Onmainthe new assertion fails (expected true to be false— the forged header passes); on this branch the full file is green (61/61).pnpm --filter @open-design/daemon typecheckpasses.