diff --git a/docs/my-website/docs/proxy/config_settings.md b/docs/my-website/docs/proxy/config_settings.md index 23c0b1498f..bfaa2776fa 100644 --- a/docs/my-website/docs/proxy/config_settings.md +++ b/docs/my-website/docs/proxy/config_settings.md @@ -199,6 +199,7 @@ router_settings: | use_chat_completions_url_for_anthropic_messages | boolean | If true, routes OpenAI `/v1/messages` requests through chat/completions instead of the Responses API. Can also be set via env var `LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES=true`. | | disable_hf_tokenizer_download | boolean | If true, it defaults to using the openai tokenizer for all models (including huggingface models). | | enable_json_schema_validation | boolean | If true, enables json schema validation for all requests. | +| enable_key_alias_format_validation | boolean | If true, validates `key_alias` format on `/key/generate` and `/key/update`. Must be 2-255 chars, start/end with alphanumeric, only allow `a-zA-Z0-9_-/.@`. Default `false`. | | disable_copilot_system_to_assistant | boolean | **DEPRECATED** - GitHub Copilot API supports system prompts. | ### general_settings - Reference diff --git a/litellm/__init__.py b/litellm/__init__.py index d75f47567a..4fc71e1270 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 072d4181c6..3b54a79a73 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 2533f0d66d..6195f34f28 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,26 @@ async def test_key_aliases_admin_sees_all(): class TestValidateKeyAliasFormat: + @pytest.fixture(autouse=True) + def reset_key_alias_flag(self): + litellm.enable_key_alias_format_validation = False + yield + litellm.enable_key_alias_format_validation = False + + 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 + + # 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") @@ -6688,7 +6707,8 @@ class TestValidateKeyAliasFormat: 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,7 +6721,7 @@ class TestValidateKeyAliasFormat: " leading", "trailing ", ] - + for alias in invalid_aliases: with pytest.raises(ProxyException) as exc: _validate_key_alias_format(alias)