fix(static-assets): also wrap admin-only Vault token verification in async_safe_get

Variant analysis on the unauthenticated /get_image SSRF surfaced one
related sink in an admin-only endpoint:
``test_hashicorp_vault_connection`` in
``config_override_endpoints.py:402`` calls
``async_client.get(f"{vault_addr}/v1/auth/token/lookup-self")`` with
no SSRF guard. ``vault_addr`` is admin-set, so the threat model is
"admin misconfig (or attacker with admin creds) pivots Vault calls
to cloud metadata or another internal IP."

Same fix shape as the unauthenticated endpoints: wrap in
``async_safe_get`` so each redirect hop is re-validated and private
networks are rejected. Admins running against a legitimate internal
Vault should add the host to ``litellm.user_url_allowed_hosts`` —
the existing escape hatch already used elsewhere in the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
user 2026-04-29 22:47:43 +00:00
parent c112bdf2c1
commit 89aa13fdf3
No known key found for this signature in database

View file

@ -391,7 +391,14 @@ async def test_hashicorp_vault_connection(
detail=f"Vault authentication failed: {e}",
)
# Step 2: Verify the token is valid via token/lookup-self
# Step 2: Verify the token is valid via token/lookup-self.
# ``vault_addr`` is admin-set; wrapping in ``async_safe_get`` prevents
# a misconfigured (or attacker-influenced) value from pivoting the
# request to cloud metadata or another internal IP. Admins running
# against an internal Vault should add the host to
# ``litellm.user_url_allowed_hosts``.
from litellm.litellm_core_utils.url_utils import async_safe_get
try:
async_client = get_async_httpx_client(
llm_provider=httpxSpecialProvider.SecretManager
@ -399,7 +406,7 @@ async def test_hashicorp_vault_connection(
lookup_url = f"{client.vault_addr}/v1/auth/token/lookup-self"
if client.vault_namespace:
headers["X-Vault-Namespace"] = client.vault_namespace
response = await async_client.get(lookup_url, headers=headers)
response = await async_safe_get(async_client, lookup_url, headers=headers)
response.raise_for_status()
except Exception as e:
raise HTTPException(