From 4c1bdd1d625fa3f1141e8af9c15423946472069e Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 5 May 2026 16:35:28 +0530 Subject: [PATCH] fix(api): use requester's workspace role for project member role updates (GHSA-x63v-p7wc-47x4) (#9014) is_workspace_admin in ProjectMemberViewSet.partial_update was derived from the target member's workspace role, not the requester's. When the target happened to be a workspace admin, all three project-role guards (L231/238/247) were bypassed regardless of who was making the request, allowing a non-admin requester to re-role a workspace admin's project membership. Compute is_workspace_admin from the requester instead and keep the target's workspace role under a distinct name for the existing new-role-vs-workspace-role cap. --- apps/api/plane/app/views/project/member.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/api/plane/app/views/project/member.py b/apps/api/plane/app/views/project/member.py index 7dfe709001..e747f573e7 100644 --- a/apps/api/plane/app/views/project/member.py +++ b/apps/api/plane/app/views/project/member.py @@ -206,11 +206,15 @@ class ProjectMemberViewSet(BaseViewSet): def partial_update(self, request, slug, project_id, pk): project_member = ProjectMember.objects.get(pk=pk, workspace__slug=slug, project_id=project_id, is_active=True) - # Fetch the workspace role of the project member - workspace_role = WorkspaceMember.objects.get( + # Fetch the target's workspace role (used to cap the new project role) + target_workspace_role = WorkspaceMember.objects.get( workspace__slug=slug, member=project_member.member, is_active=True ).role - is_workspace_admin = workspace_role == ROLE.ADMIN.value + # Fetch the requester's workspace role to decide if they may bypass project-role checks + requester_workspace_role = WorkspaceMember.objects.get( + workspace__slug=slug, member=request.user, is_active=True + ).role + is_workspace_admin = requester_workspace_role == ROLE.ADMIN.value # Check if the user is not editing their own role if they are not an admin if request.user.id == project_member.member_id and not is_workspace_admin: @@ -251,7 +255,7 @@ class ProjectMemberViewSet(BaseViewSet): ) # Cannot assign a role higher than the target's workspace role - if workspace_role in [5] and new_role in [15, 20]: + if target_workspace_role in [5] and new_role in [15, 20]: return Response( {"error": "You cannot add a user with role higher than the workspace role"}, status=status.HTTP_400_BAD_REQUEST,