mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-24 05:45:11 +00:00
Merge 768f14ead8 into c58fc0c996
This commit is contained in:
commit
d3c32bea19
2 changed files with 62 additions and 3 deletions
|
|
@ -314,6 +314,15 @@ _NESTED_CONFIG_KEYS: Final[tuple[str, ...]] = ("litellm_embedding_config", "extr
|
|||
# was an unintentional bypass.
|
||||
_NESTED_METADATA_KEYS: Final[tuple[str, ...]] = ("metadata", "litellm_metadata")
|
||||
|
||||
# Bedrock Claude Platform reads its workspace pin only from top-level call params, never from
|
||||
# metadata, where `workspace_id` is a common caller tag (spend logs, traces).
|
||||
_METADATA_CALLER_TAGS: Final[frozenset[str]] = frozenset({"workspace_id"})
|
||||
|
||||
|
||||
def _without_metadata_caller_tags(metadata: Mapping[str, object]) -> Mapping[str, object]:
|
||||
return MappingProxyType({key: value for key, value in metadata.items() if key not in _METADATA_CALLER_TAGS})
|
||||
|
||||
|
||||
# Banned request-body params. The same list applies to every entry in
|
||||
# ``_NESTED_CONFIG_KEYS`` (dicts spread as ``**kwargs`` into outbound
|
||||
# calls) and ``_NESTED_METADATA_KEYS`` (dicts read directly by integration
|
||||
|
|
@ -664,10 +673,18 @@ def is_request_body_safe(
|
|||
for metadata_key in _NESTED_METADATA_KEYS:
|
||||
metadata = _coerce_metadata_to_dict(request_body.get(metadata_key))
|
||||
if metadata is not None:
|
||||
_check_banned_params(metadata, general_settings, llm_router, model, manages_deployments=manages_deployments)
|
||||
_check_banned_params(
|
||||
_without_metadata_caller_tags(metadata),
|
||||
general_settings,
|
||||
llm_router,
|
||||
model,
|
||||
manages_deployments=manages_deployments,
|
||||
)
|
||||
if any(isinstance(key, str) and key.startswith(f"{metadata_key}[") for key in request_body):
|
||||
_check_banned_params(
|
||||
extract_nested_form_metadata(form_data=request_body, prefix=f"{metadata_key}["),
|
||||
_without_metadata_caller_tags(
|
||||
extract_nested_form_metadata(form_data=request_body, prefix=f"{metadata_key}[")
|
||||
),
|
||||
general_settings,
|
||||
llm_router,
|
||||
model,
|
||||
|
|
@ -689,7 +706,7 @@ def is_request_body_safe(
|
|||
litellm_params_metadata: Final = _coerce_metadata_to_dict(litellm_params.get("metadata"))
|
||||
if litellm_params_metadata is not None:
|
||||
_check_banned_params(
|
||||
litellm_params_metadata,
|
||||
_without_metadata_caller_tags(litellm_params_metadata),
|
||||
general_settings,
|
||||
llm_router,
|
||||
model,
|
||||
|
|
|
|||
|
|
@ -3151,6 +3151,48 @@ class TestIsRequestBodySafeBlocksClaudePlatformWorkspaceOverride:
|
|||
is True
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"request_body",
|
||||
[
|
||||
pytest.param({"metadata": {"workspace_id": "ws-1"}}, id="metadata"),
|
||||
pytest.param({"litellm_metadata": {"workspace_id": "ws-1"}}, id="litellm_metadata"),
|
||||
pytest.param({"litellm_metadata": '{"workspace_id": "ws-1"}'}, id="litellm_metadata-json"),
|
||||
pytest.param({"metadata[workspace_id]": "ws-1"}, id="form-metadata"),
|
||||
pytest.param({"litellm_params": {"metadata": {"workspace_id": "ws-1"}}}, id="litellm_params-metadata"),
|
||||
],
|
||||
)
|
||||
def test_workspace_id_metadata_tag_is_accepted(self, request_body):
|
||||
assert (
|
||||
is_request_body_safe(
|
||||
request_body={"model": "gpt-4", **request_body},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="gpt-4",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("request_body", "rejected"),
|
||||
[
|
||||
pytest.param({"extra_body": {"workspace_id": "wrkspc_attacker"}}, "workspace_id", id="extra_body"),
|
||||
pytest.param({"metadata": {"aws_workspace_id": "wrkspc_attacker"}}, "aws_workspace_id", id="alias"),
|
||||
pytest.param(
|
||||
{"metadata": {"workspace_id": "ws-1", "langfuse_host": "https://attacker.example"}},
|
||||
"langfuse_host",
|
||||
id="tag-beside-banned",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_metadata_tag_exemption_stays_narrow(self, request_body, rejected):
|
||||
with pytest.raises(ValueError, match=rejected):
|
||||
is_request_body_safe(
|
||||
request_body={"model": "gpt-4", **request_body},
|
||||
general_settings={},
|
||||
llm_router=None,
|
||||
model="gpt-4",
|
||||
)
|
||||
|
||||
|
||||
class TestIsRequestBodySafeBlocksFireworksForwardUserId:
|
||||
@pytest.mark.parametrize("value", [True, False])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue