mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix(proxy): close /organization member_delete + role-escalation gaps
Audit-B #7 and #8. 1. /organization/member_delete was not in org_admin_only_routes, so it fell through to management_routes/self_managed_routes and let any caller that reached the route delete arbitrary org memberships without the organization_role_based_access_check that member_add and member_update trigger. Adding it to org_admin_only_routes applies the same ORG_ADMIN-of-target-org gate. 2. /organization/member_update had no validation that the target user was not a global PROXY_ADMIN. An org-admin of any org could alter a PROXY_ADMIN user's per-org role. Reject this unless the caller is PROXY_ADMIN.
This commit is contained in:
parent
c7c3df2b02
commit
e3b55794ce
2 changed files with 34 additions and 0 deletions
|
|
@ -690,6 +690,13 @@ class LiteLLMRoutes(enum.Enum):
|
|||
"/organization/delete",
|
||||
"/organization/member_add",
|
||||
"/organization/member_update",
|
||||
# member_delete is equally destructive as member_add / member_update
|
||||
# and must be scoped the same way — otherwise it falls through to
|
||||
# the management_routes / self_managed_routes path and lets any
|
||||
# non-PROXY_ADMIN caller that reaches the route delete arbitrary
|
||||
# org memberships without the organization_role_based_access_check
|
||||
# that member_add / member_update trigger.
|
||||
"/organization/member_delete",
|
||||
]
|
||||
|
||||
# Routes accessible by Admin Viewer (read-only admin access)
|
||||
|
|
|
|||
|
|
@ -1064,6 +1064,33 @@ async def organization_member_update(
|
|||
},
|
||||
)
|
||||
|
||||
# Reject attempts to change the role of a global PROXY_ADMIN via
|
||||
# org-scoped operations. An org-admin of any org could otherwise
|
||||
# alter a PROXY_ADMIN user's per-org role, which has downstream
|
||||
# effects on admin UI filtering and scope derivation.
|
||||
target_user_row = await prisma_client.db.litellm_usertable.find_unique(
|
||||
where={"user_id": data.user_id}
|
||||
)
|
||||
if target_user_row is not None and getattr(
|
||||
target_user_row, "user_role", None
|
||||
) in (
|
||||
LitellmUserRoles.PROXY_ADMIN.value,
|
||||
LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY.value,
|
||||
):
|
||||
if (
|
||||
user_api_key_dict.user_role
|
||||
!= LitellmUserRoles.PROXY_ADMIN.value
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail={
|
||||
"error": (
|
||||
"Only PROXY_ADMIN may modify the organization "
|
||||
"role of a user who is a global PROXY_ADMIN."
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
# Update member role
|
||||
if data.role is not None:
|
||||
await prisma_client.db.litellm_organizationmembership.update(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue