Skip to content

fix(server): allow browser SDK request headers through CORS preflight - #1778

Merged
lidge-jun merged 2 commits into
devfrom
codex/roadmap-closeout-260815
Aug 15, 2026
Merged

fix(server): allow browser SDK request headers through CORS preflight#1778
lidge-jun merged 2 commits into
devfrom
codex/roadmap-closeout-260815

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Summary

The OpenAI and Anthropic browser SDKs send X-Stainless-* request headers describing runtime and retry state. The CORS preflight answered with a fixed Access-Control-Allow-Headers list that never mentioned them, so the browser blocked the real request before it was ever sent — every browser SDK client was unable to reach the proxy.

corsHeaders() now echoes the headers an already-allowed origin asked for, keeping the existing static list as the floor, and declares the dependency with Vary: Origin, Access-Control-Request-Headers.

The echo is gated on the origin check that already ran. It widens which headers an admitted caller may send, never which origins are admitted: a rejected origin is refused with 403 before any allow-list is built, and the preflight still carries no credential and produces no auth or account-pool side effect. Header names are normalized case-insensitively before de-duplication, so a caller re-requesting content-type cannot duplicate the entry.

Closes #1773

Verification

Run on the Linux validation host against this exact head:

bun test tests/server-auth.test.ts tests/server-live.test.ts tests/server-loopback-host-gate.test.ts tests/loopback-listener-admission.test.ts
142 pass, 0 fail, 859 expect() calls

bun x tsc --noEmit clean.

New regression table-drives /v1/messages, /v1/responses, and /v1/chat/completions: each must echo every requested Stainless header, preserve the static contract, avoid duplicating content-type, and set Vary. The rejected-origin case asserts 403 with no echoed header.

Checklist

  • Focused tests for the changed subsystem pass
  • bun x tsc --noEmit clean
  • No request bodies, keys, or account identifiers logged
  • Security boundary reviewed: origin admission is unchanged

Summary by CodeRabbit

  • Bug Fixes

    • Improved CORS preflight handling for approved origins.
    • Supports requested SDK headers while preventing duplicate headers.
    • Rejects unauthorized origins with HTTP 403 responses.
    • Added cache-safe response variation for origin and requested headers.
  • Tests

    • Added coverage for CORS behavior across message, response, and chat completion endpoints.

The OpenAI and Anthropic browser SDKs send X-Stainless-* headers describing
runtime and retry state. The preflight answered with a fixed allow-list that
never mentioned them, so the browser blocked every request before it was sent
and no browser SDK client could reach the proxy at all.

Echo the requested headers for an origin that already passed the origin gate,
keeping the static contract as the floor, and declare the dependency with
Vary. The echo widens which headers an admitted caller may send, never which
origins are admitted: a rejected origin is refused before any allow-list is
built, and the preflight still carries no credential and no auth side effect.

Closes #1773
@lidge-jun
lidge-jun merged commit 53130de into dev Aug 15, 2026
6 checks passed
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d8688d4b-351d-413f-aa90-e9cc916fb148

📥 Commits

Reviewing files that changed from the base of the PR and between 906533b and f46094a.

📒 Files selected for processing (4)
  • devlog/_plan/260815_roadmap_closeout/000_source_capture_raw.txt
  • devlog/_plan/260815_roadmap_closeout/010_unit_overview.md
  • src/server/auth-cors.ts
  • tests/server-auth.test.ts

📝 Walkthrough

Walkthrough

The PR adds roadmap closeout records and updates server CORS handling. Authorized origins can receive requested preflight headers with case-insensitive deduplication. Tests cover Stainless SDK headers across three API routes and reject unauthorized origins.

Changes

Roadmap closeout and CORS handling

Layer / File(s) Summary
Roadmap closeout records
devlog/_plan/260815_roadmap_closeout/000_source_capture_raw.txt, devlog/_plan/260815_roadmap_closeout/010_unit_overview.md
The records document issue counts, merge and closure rules, CORS requirements, provider remediation plans, prioritization, validation evidence, execution status, and explicit holds.
Dynamic CORS preflight handling
src/server/auth-cors.ts, tests/server-auth.test.ts
allowedRequestHeaders deduplicates requested headers and preserves additional header spelling. corsHeaders echoes them only for authorized origins and adds Vary: Origin, Access-Control-Request-Headers. Tests cover /v1/messages, /v1/responses, and /v1/chat/completions, including HTTP 403 responses for unauthorized origins.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: review-ready

Suggested reviewers: ingwannu, wibias

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/roadmap-closeout-260815

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f46094a754

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

CRM 프로젝트 평가 요청
인사 나누기
김병준

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove personal account data from the tracked capture

The raw transcript includes the user's full name along with unrelated private ChatGPT history titles, so committing 000_source_capture_raw.txt publishes personal account data in the repository even though the automated privacy scan does not recognize names. Remove the raw UI capture or replace it with a narrowly redacted summary before this commit is pushed.

AGENTS.md reference: AGENTS.md:L281-L282

Useful? React with 👍 / 👎.

Comment on lines +169 to +171
#1774 — Responses 전용 encrypted annotation 누출

V2 spawn_agent의 tool schema에 있는 encrypted: true가 generic openai-chat upstream으로 그대로 전달될 때, provider가 필수 message argument를 비워 반환하는 controlled A/B 재현이 있다. provider 이름별 예외가 아니라 protocol-boundary schema sanitizer로 처리해야 한다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Move unfixed security triage out of devlog

This tracked _plan transcript records a controlled reproduction and patch strategy for unresolved defect #1774, with additional unresolved credential and routing boundary analysis later in the same file. Because devlog/ is public, pushing this commit publishes pre-disclosure working notes whose history is difficult to purge; keep the raw review in .tmp/ and commit only the fix and regression evidence once the affected defects are resolved.

AGENTS.md reference: AGENTS.md:L97-L104

Useful? React with 👍 / 👎.

@Wibias
Wibias deleted the codex/roadmap-closeout-260815 branch August 15, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant