fix(mcp): keep last-wins header normalization for the tool-call hook bearer
Some checks are pending
LiteLLM Rust / rust-lint (push) Waiting to run
LiteLLM Rust / rust-test (push) Waiting to run
LiteLLM Rust / rust-wheel (push) Waiting to run

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-10-04 00:48:31 +00:00
parent afc233ec09
commit 7df0bc39cd
2 changed files with 17 additions and 2 deletions

View file

@ -6045,11 +6045,12 @@ class MCPServerManager:
if proxy_logging_obj is None:
return hook_result
inbound_authorization: Final = _raw_header_value(raw_headers, "authorization") or ""
normalized_raw: Final = {k.lower(): v for k, v in (raw_headers or {}).items()}
inbound_authorization: Final = normalized_raw.get("authorization", "")
incoming_bearer_token: Final = (
inbound_authorization[len("bearer ") :] if inbound_authorization.lower().startswith("bearer ") else None
)
incoming_subject_token: Final = self._caller_sign_in_subject_token(None, raw_headers)
incoming_subject_token: Final = self._caller_sign_in_subject_token(None, normalized_raw)
pre_hook_kwargs: Final = {
"guardrail_context": guardrail_context,

View file

@ -6992,6 +6992,20 @@ class TestMCPServerManager:
" eyJ.x.y",
id="bearer-credential-is-taken-verbatim-after-one-space",
),
pytest.param(
{"authorization": "Bearer sk-request-key", "Authorization": "Bearer eyJ.caller.jws"},
"sk-request-key",
"eyJ.caller.jws",
"eyJ.caller.jws",
id="responses-bridge-tool-authorization-overrides-the-request-key",
),
pytest.param(
{"Authorization": "Bearer eyJ.caller.jws", "authorization": "Bearer sk-request-key"},
"sk-request-key",
"sk-request-key",
None,
id="last-duplicate-case-authorization-wins",
),
],
)
async def test_pre_call_tool_check_separates_raw_bearer_from_subject(