Skip to content

fix(ai-llm-proxy): enforce server-side Origin check (403 on mismatch)#480

Merged
LukasHirt merged 1 commit into
owncloud:mainfrom
dj4oC:fix-ai-llm-proxy-origin-check
Jun 25, 2026
Merged

fix(ai-llm-proxy): enforce server-side Origin check (403 on mismatch)#480
LukasHirt merged 1 commit into
owncloud:mainfrom
dj4oC:fix-ai-llm-proxy-origin-check

Conversation

@dj4oC

@dj4oC dj4oC commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Problem

ai-llm-proxy validates the oCIS bearer token and sets CORS response headers, but has no server-side Origin check. CORS headers are advisory and enforced only by the browser, so they do not stop a non-browser or cross-site client from reaching the LLM. The repo security requirement is explicit: any LLM-calling path "must perform an explicit server-side origin check and return 403 for unexpected origins — CORS headers alone are browser-enforced and insufficient."

This came up while reviewing the new AI extensions (#475, #476, #477), which all correctly route through this proxy and rely on it being the single enforcement point — but the enforcement was missing.

Fix

Add an authoritative server-side Origin gate in handleRequest, before token validation and the LLM call:

  • Origin header present but not matching the origin derived from OCIS_URL403.
  • No Origin header → allowed through to token validation. A cross-site browser request always carries Origin, so a missing one cannot be a cross-site browser attack, and the mandatory oCIS bearer token still guards it.
  • No-op when OCIS_URL is unset (the server already refuses to start without it outside tests).

The expected origin is computed once from OCIS_URL via new URL(OCIS_URL).origin, so it compares correctly against the scheme/host/port Origin header.

Testing

  • New isOriginAllowed unit tests: matching origin, cross origin, scheme mismatch, port mismatch, missing header, unconfigured.
  • pnpm --filter ai-llm-proxy test:unit25 passed.
  • pnpm --filter ai-llm-proxy build + lint clean.

Risk

Low. Genuine calls from the oCIS web extensions are same-origin POSTs that always carry Origin: <OCIS_URL origin>, so they are unaffected. Only requests from a different (or unexpected) origin are newly rejected — which is the intent.

The proxy validated the oCIS bearer token and set CORS response headers, but
CORS headers are advisory and browser-enforced only - they do not stop a
non-browser or cross-site client from reaching the LLM. The repo security
requirement mandates an explicit server-side Origin check.

Add an authoritative Origin gate: a request whose Origin header is present but
does not match the origin derived from OCIS_URL is rejected with 403 before any
token validation or LLM call. A request with no Origin header cannot be a
cross-site browser request and stays gated by the mandatory oCIS token, so it
is allowed through. The check is a no-op when OCIS_URL is unset (the server
already refuses to start without it outside tests).

Adds isOriginAllowed unit tests (matching origin, cross origin, scheme/port
mismatch, missing header, unconfigured).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: David Walter <david.walter@kiteworks.com>
@kw-security

kw-security commented Jun 25, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@LukasHirt LukasHirt merged commit 68e2ccb into owncloud:main Jun 25, 2026
24 checks passed
@dj4oC dj4oC deleted the fix-ai-llm-proxy-origin-check branch June 25, 2026 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants