Skip to content

fix: stop leaking x-litellm-api-key to Anthropic + support OAuth tokens in passthrough#20432

Open
klaudworks wants to merge 1 commit intoBerriAI:mainfrom
klaudworks:feat/anthropic-oauth-passthrough
Open

fix: stop leaking x-litellm-api-key to Anthropic + support OAuth tokens in passthrough#20432
klaudworks wants to merge 1 commit intoBerriAI:mainfrom
klaudworks:feat/anthropic-oauth-passthrough

Conversation

@klaudworks
Copy link

@klaudworks klaudworks commented Feb 4, 2026

Summary

This PR fixes credential handling in the /anthropic/{endpoint:path} passthrough endpoint. There are two issues here - one is leaking litellm api keys to anthropic, the other is headers being improperly overwritten.

Security Fix

x-litellm-api-key was being forwarded to Anthropic. Now we strip it in forward_headers_from_request.

Bug Fixes

  • Client x-api-key was always overwritten - Server credentials overwrote client-provided API keys
  • Client Authorization header was overwritten - OAuth tokens (used by Claude Code Max subscriptions) were ignored so this didn't work: https://docs.litellm.ai/docs/tutorials/claude_code_max_subscription
  • Literal "None" sent as API key - If server had no ANTHROPIC_API_KEY configured, it sent the string "None" to Anthropic

Credential Priority (new behavior)

  1. Client x-api-key → forward as-is
  2. Client Authorization → forward as-is
  3. No client auth → use server credentials (if configured)
  4. Nothing configured → forward request without credentials (let Anthropic return auth error)

Verification

  • Built Docker image and tested passthrough endpoint with both API key and OAuth token authentication
  • Verified x-litellm-api-key is no longer forwarded to upstream providers
  • Added unit tests for header stripping logic

@vercel
Copy link

vercel bot commented Feb 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Error Error Feb 14, 2026 5:13pm

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 4, 2026

Greptile Overview

Greptile Summary

This PR addresses critical security and functionality issues in the Anthropic passthrough endpoint:

Security Fix:

  • Prevents x-litellm-api-key from being leaked to Anthropic API by stripping it in forward_headers_from_request

Credential Handling Improvements:

  • Client-provided x-api-key or Authorization headers now take precedence over server credentials
  • Fixes bug where server credentials always overwrote client credentials
  • Prevents sending literal string "None" when server has no configured API key
  • Enables OAuth token support (used by Claude Code Max subscriptions)

Implementation:
The credential priority logic correctly implements: client x-api-key → client Authorization → server credentials → no credentials (let Anthropic return auth error). The header stripping is properly tested.

Confidence Score: 4/5

  • This PR is safe to merge with one minor test coverage gap
  • The security fix for x-litellm-api-key leakage is critical and correctly implemented. The credential handling logic is sound and well-designed. However, while unit tests verify header stripping, there are no tests for the credential priority logic in anthropic_proxy_route, which is why this gets a 4 instead of 5.
  • No files require special attention - the implementation is solid

Important Files Changed

Filename Overview
litellm/passthrough/utils.py Added x-litellm-api-key to the list of headers that should not be forwarded to upstream providers, fixing the security leak
litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py Implemented credential priority logic for Anthropic passthrough: client headers take precedence over server credentials, avoiding literal "None" string
tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py Added unit tests verifying x-litellm-api-key is correctly stripped from forwarded headers

Sequence Diagram

sequenceDiagram
    participant Client
    participant Proxy as LiteLLM Proxy
    participant PassThrough as anthropic_proxy_route
    participant Utils as forward_headers_from_request
    participant Anthropic as Anthropic API

    Note over Client,Anthropic: Scenario 1: Client provides x-api-key
    Client->>Proxy: POST /anthropic/v1/messages<br/>Headers: x-litellm-api-key, x-api-key
    Proxy->>PassThrough: Forward request
    PassThrough->>PassThrough: Check headers<br/>x_api_key_header exists
    PassThrough->>PassThrough: custom_headers = {}
    PassThrough->>Utils: forward_headers_from_request()<br/>strips x-litellm-api-key
    Utils-->>PassThrough: Headers without x-litellm-api-key
    PassThrough->>Anthropic: Request with client x-api-key<br/>(no server credentials added)
    Anthropic-->>Client: Response

    Note over Client,Anthropic: Scenario 2: Client provides Authorization (OAuth)
    Client->>Proxy: POST /anthropic/v1/messages<br/>Headers: x-litellm-api-key, Authorization
    Proxy->>PassThrough: Forward request
    PassThrough->>PassThrough: Check headers<br/>auth_header exists
    PassThrough->>PassThrough: custom_headers = {}
    PassThrough->>Utils: forward_headers_from_request()<br/>strips x-litellm-api-key
    Utils-->>PassThrough: Headers with Authorization
    PassThrough->>Anthropic: Request with OAuth token<br/>(no server credentials added)
    Anthropic-->>Client: Response

    Note over Client,Anthropic: Scenario 3: No client credentials
    Client->>Proxy: POST /anthropic/v1/messages<br/>Headers: x-litellm-api-key only
    Proxy->>PassThrough: Forward request
    PassThrough->>PassThrough: Check headers<br/>no x-api-key or Authorization
    PassThrough->>PassThrough: Get server credentials
    PassThrough->>PassThrough: custom_headers = server credentials
    PassThrough->>Utils: forward_headers_from_request()<br/>strips x-litellm-api-key
    Utils-->>PassThrough: Headers without x-litellm-api-key
    PassThrough->>Anthropic: Request with server credentials
    Anthropic-->>Client: Response
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@klaudworks
Copy link
Author

klaudworks commented Feb 4, 2026

the linting failure is in a file that I did not touch:

llms/github_copilot/chat/transformation.py:1:20: F401 [*] `typing.Any` imported but unused
llms/github_copilot/chat/transformation.py:1:48: F401 [*] `typing.cast` imported but unused

@klaudworks
Copy link
Author

@ishaan-jaff I'm seeing a lot of open PRs without any comments. Do you actually process external PRs? o.w. I'll release my fork.

@krrishdholakia
Copy link
Member

@klaudworks i just merged in #21039 which deals with the OAuth issue

can you refactor to just handle the x-litellm-api-key scenario?

…ream providers

Prevent x-litellm-api-key (LiteLLM's virtual key) from being leaked
to upstream providers when _forward_headers=True is used in passthrough
endpoints.
@klaudworks
Copy link
Author

@krrishdholakia I adapted the PR

@krrishdholakia
Copy link
Member

@greptile please review this

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 14, 2026

Greptile Overview

Greptile Summary

This PR adds a security fix to strip x-litellm-api-key from headers forwarded to upstream providers via passthrough endpoints. Without this fix, the LiteLLM proxy authentication key was being forwarded to providers like Anthropic when forward_headers=True.

  • Security fix: x-litellm-api-key is now removed in BasePassthroughUtils.forward_headers_from_request() before headers are forwarded upstream, preventing credential leakage
  • Tests: Two new unit tests verify the header stripping behavior (mock-only, no network calls)
  • Note on PR scope: The PR description mentions additional fixes (credential priority changes, OAuth token forwarding, "None" string bug) that are not present in this diff. The actual code change is a single line in litellm/passthrough/utils.py. The anthropic_proxy_route in llm_passthrough_endpoints.py is unchanged, so server credentials still overwrite client-provided x-api-key via the {**request_headers, **headers} merge order, and "{}".format(None) still produces "None" when no ANTHROPIC_API_KEY is configured

Confidence Score: 4/5

  • The single-line security fix is correct and safe to merge; it only strips an internal auth header from forwarded requests.
  • The actual code change is minimal and clearly correct — it adds x-litellm-api-key to the list of headers stripped before forwarding to upstream providers. The security fix addresses a real credential leakage issue. Score is 4 instead of 5 because the PR description claims several additional fixes (credential priority, OAuth support, "None" string fix) that are not present in the diff, which creates a gap between documented and actual behavior.
  • No files in the changeset require special attention. However, litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py (not in this PR) still has the "None" string and credential overwrite issues described in the PR description.

Important Files Changed

Filename Overview
litellm/passthrough/utils.py Single-line security fix: strips x-litellm-api-key from forwarded headers to prevent leaking LiteLLM proxy authentication credentials to upstream providers. The change is correct and placed in the right location alongside existing header stripping for content-length and host.
tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py Adds two unit tests for header stripping in BasePassthroughUtils.forward_headers_from_request: one verifying x-litellm-api-key removal, another verifying host and content-length removal. Tests are mock-only (no network calls), which is correct per repository rules. Missing newline at end of file.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Proxy as LiteLLM Proxy
    participant FwdHeaders as forward_headers_from_request
    participant Anthropic as Anthropic API

    Client->>Proxy: Request with headers including x-litellm-api-key
    Proxy->>Proxy: Build custom_headers with server credentials
    Proxy->>FwdHeaders: request_headers, custom_headers, forward_headers=True
    
    Note over FwdHeaders: Strip content-length
    Note over FwdHeaders: Strip host
    Note over FwdHeaders: Strip x-litellm-api-key (NEW)
    Note over FwdHeaders: Merge request + custom headers
    
    FwdHeaders-->>Proxy: Merged headers without x-litellm-api-key
    Proxy->>Anthropic: Forward request with safe headers
Loading

Last reviewed commit: 27863e3

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile


assert "host" not in result
assert "content-length" not in result
assert result.get("content-type") == "application/json" No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing newline at end of file

The file is missing a trailing newline, which can cause issues with some tools and produces a noisy diff marker. Add a newline at the end.

Suggested change
assert result.get("content-type") == "application/json"
assert result.get("content-type") == "application/json"

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@klaudworks
Copy link
Author

@krrishdholakia

@klaudworks
Copy link
Author

@krrishdholakia do you still plan to merge this?

@klaudworks
Copy link
Author

klaudworks commented Feb 25, 2026

@krrishdholakia you asked me to modify this after separately merging a subset of this PR which was created AFTER this PR. I pulled out the oauth changes which you explicitly asked for so please review this or close the PR

@klaudworks
Copy link
Author

@krrishdholakia ping. I'd be glad if I could use an upstream litellm image without leaking my litellm api keys to Anthropic.

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.

2 participants