fix(mcp): fail closed on DB outage in BYOK credential check

`_check_byok_credential` previously returned silently when `prisma_client`
was None, bypassing BYOK ownership validation during database-outage
windows. Any proxy-authenticated user could invoke BYOK-protected MCP
tools without a stored credential during the outage window.

Now raises HTTP 503 with a structured error so the flow fails closed.

Regression test asserts 503 is raised when `prisma_client` is None.

Reported by @brodmart in GHSA-6762-2m23-5mxp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
user 2026-04-24 18:44:57 +00:00
parent f5b4564466
commit fea402c580
No known key found for this signature in database
2 changed files with 41 additions and 1 deletions

View file

@ -1952,7 +1952,18 @@ if MCP_AVAILABLE:
from litellm.proxy.proxy_server import prisma_client
if prisma_client is None:
return
# Fail closed on DB unavailability: returning here previously
# bypassed the ownership check and let any proxy-authenticated
# caller invoke BYOK tools during outage windows.
raise HTTPException(
status_code=503,
detail={
"error": "byok_auth_unavailable",
"server_id": mcp_server.server_id,
"server_name": mcp_server.server_name or mcp_server.name,
"message": "BYOK credential check requires a database connection.",
},
)
credential = await get_user_credential(
prisma_client=prisma_client,

View file

@ -564,6 +564,35 @@ async def test_check_byok_credential_has_credential():
await _check_byok_credential(server, user_auth)
@pytest.mark.asyncio
async def test_check_byok_credential_db_unavailable_fails_closed():
"""BYOK server with no prisma_client → 503, not silent pass.
Regression for GHSA-6762: previously returned silently, bypassing the
ownership check during DB outage windows.
"""
from litellm.proxy._experimental.mcp_server.server import _check_byok_credential
from litellm.proxy._types import UserAPIKeyAuth
from litellm.types.mcp_server.mcp_server_manager import MCPServer
server = MCPServer(
server_id="byok-4",
name="byok-server",
transport=MCPTransport.http,
is_byok=True,
)
user_auth = UserAPIKeyAuth(user_id="user-55", api_key="sk-test")
with patch("litellm.proxy.proxy_server.prisma_client", None):
with pytest.raises(HTTPException) as exc_info:
await _check_byok_credential(server, user_auth)
assert exc_info.value.status_code == 503
detail: Any = exc_info.value.detail
assert detail["error"] == "byok_auth_unavailable"
assert detail["server_id"] == "byok-4"
# ---------------------------------------------------------------------------
# Security regression tests for AO2kf_-9 / GHSA-jg3h:
# Unauthenticated /v1/mcp/oauth/authorize previously allowed an attacker to