Skip to content

Same-origin guard trusts forgeable Sec-Fetch-Site header (fail-open for non-browser clients) #7041

Description

@zenprocess

Summary

The daemon's same-origin guard (isLocalSameOrigin, origin-validation.ts) treats a
client-supplied Sec-Fetch-Site: same-origin header as sufficient authorization when
the Origin header is absent:

GET /api/app-config            -> 403 cross-origin request rejected
GET /api/app-config
    -H 'Sec-Fetch-Site: same-origin'   -> 200 (full app config)

Sec-Fetch-Site is set by user agents and cannot be forged by JavaScript, but it is
trivially forgeable by any non-browser HTTP client (curl, scripts). The guarded
endpoints (/api/app-config, MCP oauth/install routes, /api/dir-exists, …) therefore
rely on a header any LAN attacker can set.

Impact

With API auth enabled, these endpoints are the only thing between a LAN client and
daemon-config mutation (flipping onboarding state, agent selection, triggering OAuth
install flows). Low severity in practice, but the guard is load-bearing when
OD_API_TOKEN enforcement is on.

Suggested fix

Fail closed: when the request host is not loopback, require an Origin header that
matches OD_ALLOWED_ORIGINS (or valid Bearer auth). Use Sec-Fetch-Site: same-origin
only as a secondary signal for real browsers that omit Origin on same-origin GETs —
never as the sole grant. The case "Origin absent + no Sec-Fetch-Site" from a
non-browser client must be denied.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity vulnerabilities or hardening

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions