-
Notifications
You must be signed in to change notification settings - Fork 3.9k
fix: prevent privilege escalation in project member role updates #8833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -226,21 +226,36 @@ def partial_update(self, request, slug, project_id, pk): | |||||||||||||||||
| is_active=True, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| if workspace_role in [5] and int(request.data.get("role", project_member.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, | ||||||||||||||||||
| ) | ||||||||||||||||||
| if "role" in request.data: | ||||||||||||||||||
| # Only Admins can modify roles | ||||||||||||||||||
| if requested_project_member.role < ROLE.ADMIN.value and not is_workspace_admin: | ||||||||||||||||||
| return Response( | ||||||||||||||||||
| {"error": "You do not have permission to update roles"}, | ||||||||||||||||||
| status=status.HTTP_403_FORBIDDEN, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| if ( | ||||||||||||||||||
| "role" in request.data | ||||||||||||||||||
| and int(request.data.get("role", project_member.role)) > requested_project_member.role | ||||||||||||||||||
| and not is_workspace_admin | ||||||||||||||||||
| ): | ||||||||||||||||||
| return Response( | ||||||||||||||||||
| {"error": "You cannot update a role that is higher than your own role"}, | ||||||||||||||||||
| status=status.HTTP_400_BAD_REQUEST, | ||||||||||||||||||
| ) | ||||||||||||||||||
| # Cannot modify a member whose role is equal to or higher than your own | ||||||||||||||||||
| if project_member.role >= requested_project_member.role and not is_workspace_admin: | ||||||||||||||||||
|
Comment on lines
+229
to
+238
|
||||||||||||||||||
| return Response( | ||||||||||||||||||
| {"error": "You cannot update the role of a member with a role equal to or higher than your own"}, | ||||||||||||||||||
| status=status.HTTP_403_FORBIDDEN, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| new_role = int(request.data.get("role")) | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhandled ValueError on non-numeric role input If 🛡️ Proposed fix+ try:
+ new_role = int(request.data.get("role"))
+ except (ValueError, TypeError):
+ return Response(
+ {"error": "Invalid role value"},
+ status=status.HTTP_400_BAD_REQUEST,
+ )
- new_role = int(request.data.get("role"))📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| # Cannot assign a role equal to or higher than your own | ||||||||||||||||||
| if new_role >= requested_project_member.role and not is_workspace_admin: | ||||||||||||||||||
| return Response( | ||||||||||||||||||
|
Comment on lines
+244
to
+248
|
||||||||||||||||||
| {"error": "You cannot assign a role equal to or higher than your own"}, | ||||||||||||||||||
| status=status.HTTP_403_FORBIDDEN, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| # Cannot assign a role higher than the target's workspace role | ||||||||||||||||||
| if 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, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
||||||||||||||||||
| # Enforce invariant: workspace admins must not have a lower project role | |
| if is_workspace_admin and new_role < ROLE.ADMIN.value: | |
| return Response( | |
| {"error": "You cannot set a workspace admin's project role lower than admin"}, | |
| status=status.HTTP_400_BAD_REQUEST, | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change introduces security-critical authorization logic for role updates, but there doesn’t appear to be contract/unit coverage for the project member role-update endpoint. Given existing contract tests for other project/workspace endpoints under
apps/api/plane/tests/contract/, add automated tests for the scenarios in the PR test plan (Guest/Member forbidden; Admin demotion only; workspace-admin bypass; non-role patch still allowed).