fix(mcp): hash connection credentials in auth failure metadata

This commit is contained in:
Joshua Valluru 2026-09-21 16:26:52 -07:00
parent 23ea0ee428
commit 2c9faf2c40
3 changed files with 13 additions and 10 deletions

View file

@ -3300,7 +3300,7 @@ class UserAPIKeyAuth(LiteLLM_VerificationTokenView): # the expected response ob
normalized = api_key
if normalized[:7].lower() == "bearer ":
normalized = normalized[7:]
if normalized.startswith("sk-"):
if normalized.startswith(("sk-", "llm_caccess_", "llm_crefresh_")):
return hash_token(normalized)
from litellm.proxy.auth.handle_jwt import JWTHandler

View file

@ -594,9 +594,10 @@ async def test_resolved_identity_exported_on_auth_failure():
@pytest.mark.asyncio
async def test_auth_failure_without_resolved_identity_still_logs():
@pytest.mark.parametrize("api_key", ["sk-unknown", "llm_caccess_sealed-test-access", "llm_crefresh_sealed-test-refresh"])
async def test_auth_failure_without_resolved_identity_still_logs(api_key):
"""When auth fails before any identity is resolved (e.g. an unknown key),
the handler must still log a usable object carrying the raw api key and
the handler must still log a usable object carrying the hashed api key and
route, not crash on the missing identity."""
handler = UserAPIKeyAuthExceptionHandler()
@ -625,14 +626,14 @@ async def test_auth_failure_without_resolved_identity_still_logs():
{},
"/v1/chat/completions",
None,
"sk-unknown",
api_key,
)
logged = mock_hook.call_args[1]["user_api_key_dict"]
# Raw key must NOT land on the object — it would be promoted into telemetry
# as litellm.api_key.hash and leak a real sk-... to anyone reading the trace.
assert logged.api_key != "sk-unknown"
assert logged.api_key == UserAPIKeyAuth(api_key="sk-unknown").api_key
assert logged.api_key != api_key
assert logged.api_key == UserAPIKeyAuth(api_key=api_key).api_key
assert logged.request_route == "/v1/chat/completions"

View file

@ -48,8 +48,9 @@ def test_the_server_sets_a_marker_by_assignment_after_construction(marker):
assert getattr(auth, marker) == "set-by-the-server"
def test_a_virtual_key_is_hashed_out_of_the_auth_object():
raw_key = "sk-1234567890abcdefghij"
@pytest.mark.parametrize("prefix", ["sk-", "llm_caccess_", "llm_crefresh_"])
def test_a_virtual_key_is_hashed_out_of_the_auth_object(prefix):
raw_key = prefix + "1234567890abcdefghij"
auth = UserAPIKeyAuth(api_key=raw_key)
@ -57,8 +58,9 @@ def test_a_virtual_key_is_hashed_out_of_the_auth_object():
assert auth.token == auth.api_key
def test_a_bearer_prefixed_key_hashes_the_same_as_the_bare_key():
raw_key = "sk-1234567890abcdefghij"
@pytest.mark.parametrize("prefix", ["sk-", "llm_caccess_", "llm_crefresh_"])
def test_a_bearer_prefixed_key_hashes_the_same_as_the_bare_key(prefix):
raw_key = prefix + "1234567890abcdefghij"
assert UserAPIKeyAuth(api_key=f"Bearer {raw_key}").token == UserAPIKeyAuth(api_key=raw_key).token