mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-07 04:24:12 +00:00
chore(proxy): also scrub pass_through_endpoints[].target from DB overlay
A pass-through endpoint's ``target`` field is passed through ``create_pass_through_route`` into ``get_instance_fn`` during config load. A PROXY_ADMIN persisting ``target: "s3://attacker/m.i"`` via the DB-overlay ``pass_through_endpoints`` write path was not covered by the previous scrub matrix, so the remote module load would still reach the loader because the YAML-load chain has ``config_file_path`` set. Walk each entry in ``general_settings.pass_through_endpoints`` and null out any ``target`` that starts with ``s3://`` or ``gcs://``. The entry itself is preserved so the path-registration helper can choose how to handle a missing target (the existing code skips the route when ``target is None``). Adds two regression tests.
This commit is contained in:
@@ -3203,6 +3203,25 @@ def _scrub_db_overlay_remote_module_loads(section: str, db_value: Any) -> Any:
|
||||
jwt.get("custom_validate"),
|
||||
)
|
||||
jwt["custom_validate"] = None
|
||||
# ``pass_through_endpoints`` is a list of dicts whose ``target``
|
||||
# is passed through ``create_pass_through_route`` →
|
||||
# ``get_instance_fn``. A DB-overlay ``target: "s3://attacker/m.i"``
|
||||
# would otherwise reach the loader because the YAML-load chain
|
||||
# has ``config_file_path`` set.
|
||||
pte = sanitized.get("pass_through_endpoints")
|
||||
if isinstance(pte, list):
|
||||
for entry in pte:
|
||||
if isinstance(entry, dict) and _is_remote_module_url(
|
||||
entry.get("target")
|
||||
):
|
||||
verbose_proxy_logger.warning(
|
||||
"Refused remote-URL target from DB-overlay "
|
||||
"general_settings.pass_through_endpoints "
|
||||
"(path=%r): %r",
|
||||
entry.get("path"),
|
||||
entry.get("target"),
|
||||
)
|
||||
entry["target"] = None
|
||||
return sanitized
|
||||
|
||||
|
||||
|
||||
@@ -71,6 +71,35 @@ def test_custom_provider_map_custom_handler_stripped():
|
||||
assert cleaned["custom_provider_map"][1]["custom_handler"] is None
|
||||
|
||||
|
||||
def test_pass_through_endpoints_target_stripped():
|
||||
overlay = {
|
||||
"pass_through_endpoints": [
|
||||
{"path": "/ok", "target": "my_module.legit_handler"},
|
||||
{"path": "/bad-s3", "target": "s3://attacker/m.handler"},
|
||||
{"path": "/bad-gcs", "target": "gcs://attacker/m.handler"},
|
||||
]
|
||||
}
|
||||
cleaned = _scrub_db_overlay_remote_module_loads("general_settings", overlay)
|
||||
# Legit dotted-name target preserved
|
||||
assert cleaned["pass_through_endpoints"][0]["target"] == "my_module.legit_handler"
|
||||
# Both remote URLs stripped to None — entry remains so the path
|
||||
# registration can still be skipped explicitly downstream
|
||||
assert cleaned["pass_through_endpoints"][1]["target"] is None
|
||||
assert cleaned["pass_through_endpoints"][2]["target"] is None
|
||||
# Sibling fields preserved
|
||||
assert cleaned["pass_through_endpoints"][0]["path"] == "/ok"
|
||||
assert cleaned["pass_through_endpoints"][1]["path"] == "/bad-s3"
|
||||
|
||||
|
||||
def test_pass_through_endpoints_non_list_passthrough():
|
||||
# If pass_through_endpoints is mistyped (not a list), the scrub
|
||||
# must not raise.
|
||||
cleaned = _scrub_db_overlay_remote_module_loads(
|
||||
"general_settings", {"pass_through_endpoints": "not-a-list"}
|
||||
)
|
||||
assert cleaned["pass_through_endpoints"] == "not-a-list"
|
||||
|
||||
|
||||
def test_litellm_jwtauth_custom_validate_stripped():
|
||||
overlay = {
|
||||
"litellm_jwtauth": {
|
||||
|
||||
Reference in New Issue
Block a user