Merge pull request #26464 from BerriAI/litellm_team_metadata_hardening
Some checks failed
Unit Tests: Security / security (push) Has been cancelled
Unit Tests: Caching (Redis) / caching-redis (push) Has been cancelled
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-utils (push) Has been cancelled
Unit Tests: Proxy DB Operations / auth-checks (push) Has been cancelled
Unit Tests: Proxy DB Operations / budgets (push) Has been cancelled
Unit Tests: Proxy DB Operations / custom-logging (push) Has been cancelled
Unit Tests: Proxy DB Operations / db-and-spend (push) Has been cancelled
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Has been cancelled
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Has been cancelled
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Has been cancelled
Unit Tests: Proxy DB Operations / key-generation (push) Has been cancelled
Unit Tests: Proxy DB Operations / logging-misc (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-runtime (push) Has been cancelled
Unit Tests: Proxy DB Operations / proxy-server-core (push) Has been cancelled
Unit Tests: Proxy DB Operations / schema-migration (push) Has been cancelled

[Fix] Harden team metadata handling in /team/new and /team/update
This commit is contained in:
yuneng-jiang 2026-04-24 17:57:15 -07:00 committed by GitHub
commit 9521b74e9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -159,6 +159,18 @@ async def _verify_team_access(
class TeamMemberBudgetHandler:
"""Helper class to handle team member budget, RPM, and TPM limit operations"""
# Metadata keys that are owned and set by the server. Callers must not be
# able to inject or overwrite these via request payloads.
SYSTEM_MANAGED_METADATA_KEYS = ("team_member_budget_id",)
@staticmethod
def strip_system_managed_metadata_keys(metadata: Optional[dict]) -> None:
"""Remove server-owned metadata keys from a caller-supplied dict."""
if not isinstance(metadata, dict):
return
for key in TeamMemberBudgetHandler.SYSTEM_MANAGED_METADATA_KEYS:
metadata.pop(key, None)
@staticmethod
def should_create_budget(
team_member_budget: Optional[float] = None,
@ -1040,6 +1052,8 @@ async def new_team( # noqa: PLR0915
_model_id = model_dict.id
## Create Team Member Budget Table
if isinstance(data.metadata, dict):
TeamMemberBudgetHandler.strip_system_managed_metadata_keys(data.metadata)
data_json = data.json()
## Handle Object Permission - MCP, Vector Stores etc.
@ -1730,6 +1744,13 @@ async def update_team( # noqa: PLR0915
updated_kv = data.json(exclude_unset=True)
# Drop server-owned metadata keys from caller input so they can only
# be written by the same code path that creates the underlying rows.
if isinstance(updated_kv.get("metadata"), dict):
TeamMemberBudgetHandler.strip_system_managed_metadata_keys(
updated_kv["metadata"]
)
# Check budget_duration and budget_reset_at
_set_budget_reset_at(data, updated_kv)