mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(proxy): wrap bare-string user_url_allowed_hosts as one-element list
Address greptile review feedback on PR #27034. list("internal.corp") splits a string into individual characters, so an operator following the SSRFError hint who writes a bare string instead of a YAML list: user_url_allowed_hosts: internal.corp would silently end up with ["i", "n", "t", ...], none of which match a real hostname. Wrap a bare string as a one-element list so the operator's intent is preserved. Adds a regression test. Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
This commit is contained in:
parent
490e0ed6ca
commit
3bf57ba6b9
2 changed files with 53 additions and 1 deletions
|
|
@ -4074,7 +4074,10 @@ class ProxyConfig:
|
|||
"user_url_allowed_hosts", None
|
||||
)
|
||||
if _user_url_allowed_hosts is not None:
|
||||
litellm.user_url_allowed_hosts = list(_user_url_allowed_hosts)
|
||||
if isinstance(_user_url_allowed_hosts, str):
|
||||
litellm.user_url_allowed_hosts = [_user_url_allowed_hosts]
|
||||
else:
|
||||
litellm.user_url_allowed_hosts = list(_user_url_allowed_hosts)
|
||||
## BUDGET RESCHEDULER ##
|
||||
proxy_budget_rescheduler_min_time = general_settings.get(
|
||||
"proxy_budget_rescheduler_min_time", proxy_budget_rescheduler_min_time
|
||||
|
|
|
|||
|
|
@ -434,3 +434,52 @@ async def test_general_settings_url_validation_string_value(raw_value, expected)
|
|||
finally:
|
||||
os.unlink(temp_file_path)
|
||||
litellm.user_url_validation = original_validation
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_general_settings_url_allowed_hosts_bare_string():
|
||||
"""
|
||||
A bare string value for user_url_allowed_hosts in YAML must be wrapped in
|
||||
a one-element list rather than passed through list(...), which would split
|
||||
it into characters. Operators following the SSRFError hint may write
|
||||
`user_url_allowed_hosts: internal.corp` and reasonably expect that single
|
||||
host to be allowlisted.
|
||||
"""
|
||||
import tempfile
|
||||
|
||||
import yaml
|
||||
|
||||
config_content = {
|
||||
"model_list": [
|
||||
{
|
||||
"model_name": "test-model",
|
||||
"litellm_params": {"model": "openai/gpt-4", "api_key": "test-key"},
|
||||
}
|
||||
],
|
||||
"general_settings": {
|
||||
"user_url_allowed_hosts": "internal.corp",
|
||||
},
|
||||
}
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
mode="w", suffix=".yaml", delete=False
|
||||
) as temp_file:
|
||||
yaml.dump(config_content, temp_file)
|
||||
temp_file_path = temp_file.name
|
||||
|
||||
original_hosts = litellm.user_url_allowed_hosts
|
||||
|
||||
try:
|
||||
proxy_config = ProxyConfig()
|
||||
await proxy_config.load_config(
|
||||
router=None,
|
||||
config_file_path=temp_file_path,
|
||||
)
|
||||
|
||||
assert litellm.user_url_allowed_hosts == ["internal.corp"], (
|
||||
"Bare-string user_url_allowed_hosts must be wrapped as a one-element "
|
||||
f"list, not split into characters. Got {litellm.user_url_allowed_hosts!r}"
|
||||
)
|
||||
finally:
|
||||
os.unlink(temp_file_path)
|
||||
litellm.user_url_allowed_hosts = original_hosts
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue