diff --git a/litellm/__init__.py b/litellm/__init__.py index d75f47567a5..4fc71e12700 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -305,6 +305,9 @@ return_response_headers: bool = ( False # get response headers from LLM Api providers - example x-remaining-requests, ) enable_json_schema_validation: bool = False +enable_key_alias_format_validation: bool = ( + False # opt-in validation of key_alias format on /key/generate and /key/update +) #################### logging: bool = True enable_loadbalancing_on_batch_endpoints: Optional[bool] = None diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 072d4181c68..3b54a79a738 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -5041,12 +5041,18 @@ def _validate_key_alias_format(key_alias: Optional[str]) -> None: """ Validate the format of the key_alias. - Rules: + Gated behind ``litellm.enable_key_alias_format_validation`` (default **False**). + When disabled, no validation is performed so existing workflows are not broken. + + Rules (when enabled): - None is OK (no alias). - Otherwise must be 2–255 chars - start/end with alphanumeric - - only allow a-zA-Z0-9_-/. + - only allow a-zA-Z0-9_-/.@ """ + if not litellm.enable_key_alias_format_validation: + return + if key_alias is None: return diff --git a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py index 2533f0d66d9..dc79322d57b 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py @@ -2,6 +2,7 @@ import json import os import sys +import litellm import pytest import yaml from fastapi.testclient import TestClient @@ -6672,8 +6673,21 @@ async def test_key_aliases_admin_sees_all(): class TestValidateKeyAliasFormat: + def test_validation_skipped_when_flag_disabled(self): + """When enable_key_alias_format_validation is False (default), no validation occurs.""" + from litellm.proxy.management_endpoints.key_management_endpoints import _validate_key_alias_format + + litellm.enable_key_alias_format_validation = False + # Even invalid aliases should pass silently when the flag is off + _validate_key_alias_format(None) + _validate_key_alias_format("") + _validate_key_alias_format("!invalid!") + _validate_key_alias_format("a" * 256) + def test_validate_key_alias_format_valid(self): from litellm.proxy.management_endpoints.key_management_endpoints import _validate_key_alias_format + + litellm.enable_key_alias_format_validation = True # Valid cases _validate_key_alias_format(None) # OK _validate_key_alias_format("valid-alias") @@ -6684,11 +6698,13 @@ class TestValidateKeyAliasFormat: _validate_key_alias_format("my-key-123") _validate_key_alias_format("user/user@example.com") _validate_key_alias_format("team/user@example.com") + litellm.enable_key_alias_format_validation = False def test_validate_key_alias_format_invalid(self): from litellm.proxy.management_endpoints.key_management_endpoints import _validate_key_alias_format from litellm.proxy._types import ProxyException - + + litellm.enable_key_alias_format_validation = True invalid_aliases = [ "", # empty " ", # whitespace @@ -6701,9 +6717,10 @@ class TestValidateKeyAliasFormat: " leading", "trailing ", ] - + for alias in invalid_aliases: with pytest.raises(ProxyException) as exc: _validate_key_alias_format(alias) assert str(exc.value.code) == "400" assert "Invalid key_alias format" in str(exc.value.message) + litellm.enable_key_alias_format_validation = False