Skip to content

fix(openrouter): stop leaking Anthropic auth headers to fallback providers - #8

Merged
0xPuncker merged 1 commit into
mainfrom
feat/run-podman-containers
Jun 25, 2026
Merged

fix(openrouter): stop leaking Anthropic auth headers to fallback providers#8
0xPuncker merged 1 commit into
mainfrom
feat/run-podman-containers

Conversation

@0xPuncker

Copy link
Copy Markdown
Owner

Summary

The OpenRouter fallback was returning 404 on every real request — not because of the model slug or endpoint (both correct), but because the proxy leaked Claude Code's x-api-key header to OpenRouter.

Root cause

buildProviderHeaders forwarded all of Claude Code's incoming headers to OpenRouter/Z.AI, stripping only 4 hop-by-hop headers (authorization, transfer-encoding, connection, host). Claude Code always sends x-api-key (its Anthropic auth header). When OpenRouter receives a stray x-api-key, its privacy/guardrail layer routes the request into a restricted data-policy path and returns:

404: No endpoints available matching your guardrail restrictions and data policy

The proxy logged the gzip-compressed error body as raw bytes (� ��1), which hid the real message.

Reproduced deterministically against live OpenRouter:

  • POST /api/v1/messages with ~anthropic/claude-opus-latest, no x-api-key200
  • same request with x-api-key404 (guardrail)

Fix

Strip Anthropic-specific routing/auth headers from the cross-provider passthrough in buildProviderHeaders:
x-api-key, anthropic-version, anthropic-beta, anthropic-dangerous-direct-browser-access, plus content-length (recomputed after cleanBody). Refactored both branches (zai + openrouter) to share one blockedForwardHeaders deny-list, with case-insensitive matching.

Verification

  • tsc + eslint clean; 102/102 tests pass (the existing OpenRouter test now also asserts x-api-key/anthropic-* are stripped and OpenRouter's own auth/attribution headers are present).
  • End-to-end through the deployed proxy:
    model conversion (openrouter): claude-opus-4-8 → ~anthropic/claude-opus-latest
    → 🌐 OpenRouter ▸ ~anthropic/claude-opus-latest ▸ retrying
    ← ✅ OPENROUTER 200 | recovered
    
    Response served by anthropic/claude-4.8-opus via OpenRouter — full Opus, no downgrade, no 404.

Follow-up to #6 (which fixed the Opus→Sonnet mapping; this fixes why that corrected slug still 404'd).

…iders

buildProviderHeaders forwarded all of Claude Code's incoming headers to
OpenRouter/Z.AI except 4 hop-by-hop ones, including x-api-key. OpenRouter
treats a stray x-api-key as a restricted data-policy request and returns
'404: No endpoints available matching your guardrail restrictions' — so
the OpenRouter fallback was dead for every real (Claude Code) request,
even though the model slug and endpoint were correct.

Strip Anthropic-specific routing/auth headers (x-api-key, anthropic-version,
anthropic-beta, anthropic-dangerous-direct-browser-access) and content-length
(recomputed after cleanBody) from the cross-provider passthrough. Verified
end-to-end: OpenRouter now returns 200 with full Opus via ~anthropic/claude-opus-latest.
@0xPuncker
0xPuncker force-pushed the feat/run-podman-containers branch from e676c40 to 6ccfc70 Compare June 24, 2026 20:04
@0xPuncker
0xPuncker merged commit fc0e4b0 into main Jun 25, 2026
3 checks passed
@0xPuncker
0xPuncker deleted the feat/run-podman-containers branch June 25, 2026 12:44
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.

1 participant