Skip to content

fix(api): use requester's workspace role in project member role updates (GHSA-x63v-p7wc-47x4)#9014

Merged
sriramveeraghanta merged 1 commit intopreviewfrom
fix/project-member-role-update-workspace-admin-subject
May 5, 2026
Merged

fix(api): use requester's workspace role in project member role updates (GHSA-x63v-p7wc-47x4)#9014
sriramveeraghanta merged 1 commit intopreviewfrom
fix/project-member-role-update-workspace-admin-subject

Conversation

@sriramveeraghanta
Copy link
Copy Markdown
Member

@sriramveeraghanta sriramveeraghanta commented May 4, 2026

Summary

  • ProjectMemberViewSet.partial_update derived is_workspace_admin 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 (lines 231 / 238 / 247) were bypassed regardless of who made the request — letting a non-admin requester re-role a workspace admin's project membership.
  • This patch computes is_workspace_admin from the requester (request.user) and renames the target lookup to target_workspace_role, which is still used to cap new_role against the target's workspace role.
  • Related to GHSA-x63v-p7wc-47x4 — the original PoC (Member promotes Guest → Member) was already blocked by #8833 (GHSA-494h-3rcq-5g3c). This fix closes a latent edge case in the same authorization block surfaced while verifying the advisory.

Trace check

Scenario Before After
Member attacker → Guest target, payload {"role": 15} (advisory PoC) 403 403 ✓
Member attacker → workspace-admin target who is Project Guest, payload {"role": 20} passes (bug) 403 ✓
Workspace admin (Project Member) updates someone's project role passes passes ✓
Project Member self-edits own role 400 400 ✓

Test plan

  • Manual: as Project Member, attempt PATCH /workspaces/{slug}/projects/{id}/members/{pk}/ against a target whose workspace role is Admin — confirm 403.
  • Manual: as Workspace Admin (with project Member role), confirm role updates still succeed.
  • Manual: confirm self-role-update still blocked for non-WS-admins.
  • CI checks pass.

Summary by CodeRabbit

  • Bug Fixes
    • Improved member role management by ensuring role updates are validated against the correct user permissions. Member role assignments now properly enforce role hierarchy constraints based on the requester's authorization level rather than the target member's current role.

…tes (GHSA-x63v-p7wc-47x4)

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.
Copilot AI review requested due to automatic review settings May 4, 2026 18:55
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

The ProjectMemberViewSet.partial_update method now correctly fetches both the target member's and requester's workspace roles, using the requester's role to determine admin status and the target member's role to constrain assignable role levels.

Changes

Authorization Logic Fix

Layer / File(s) Summary
Role Fetching & Admin Determination
apps/api/plane/app/views/project/member.py
Fetch both target_workspace_role (for the member being updated) and requester_workspace_role (for the user performing the update). Compute is_workspace_admin from the requester's workspace role instead of the target member's role.
Role Assignment Constraint
apps/api/plane/app/views/project/member.py
Update the role-ceiling constraint during partial updates to reference target_workspace_role instead of the prior workspace_role variable, ensuring members cannot be assigned roles above their own workspace role level.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • makeplane/plane#8833: Modifies the same ProjectMemberViewSet.partial_update method's role-authorization logic, determining which workspace role and requester/target role distinction are used for admin checks and constraints.

Suggested labels

ready to merge

Suggested reviewers

  • dheeru0198

Poem

🐰 A rabbit hops through roles anew,
Requester's crowns now checked true!
Target's cap stays firm and tight,
Admin checks done just right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main bug fix: using the requester's workspace role instead of the target's in project member role updates.
Description check ✅ Passed The description is comprehensive but incomplete according to the template. While it provides detailed summary and test plan, it is missing the 'Type of Change', 'Screenshots and Media', and 'References' sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/project-member-role-update-workspace-admin-subject

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an authorization bug in the project member role update endpoint where is_workspace_admin was incorrectly derived from the target member’s workspace role rather than the requester’s, allowing project-role guard checks to be bypassed when the target happened to be a workspace admin (GHSA-x63v-p7wc-47x4).

Changes:

  • Compute is_workspace_admin based on the requester’s WorkspaceMember.role instead of the target’s.
  • Rename the target role lookup to target_workspace_role and continue using it to cap disallowed project role assignments for workspace guests.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/api/plane/app/views/project/member.py (1)

258-262: ⚡ Quick win

Add symmetric workspace-role constraint to partial_update method.

The constraint at lines 258-262 correctly prevents workspace guests (role=5) from being promoted to higher project roles. However, the create method (lines 73-77) prevents workspace admins (role=20) from assigning lower project roles to members, while partial_update lacks a symmetric constraint preventing workspace admins from being demoted.

Consider adding:

if target_workspace_role in [20] and new_role in [5, 15]:
    return Response(
        {"error": "You cannot assign a role lower than the workspace role"},
        status=status.HTTP_400_BAD_REQUEST,
    )

This ensures workspace admins cannot have their project role demoted in the same way guests cannot be improperly promoted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/app/views/project/member.py` around lines 258 - 262, The
partial_update method currently blocks promoting workspace guests
(target_workspace_role == 5) to higher project roles but lacks the symmetric
check present in create; add a check in partial_update that if
target_workspace_role == 20 and new_role in [5, 15] it returns
Response({"error": "You cannot assign a role lower than the workspace role"},
status=status.HTTP_400_BAD_REQUEST) so workspace admins cannot be demoted to
lower project roles; use the same Response and status.HTTP_400_BAD_REQUEST
pattern as the existing constraint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/api/plane/app/views/project/member.py`:
- Around line 258-262: The partial_update method currently blocks promoting
workspace guests (target_workspace_role == 5) to higher project roles but lacks
the symmetric check present in create; add a check in partial_update that if
target_workspace_role == 20 and new_role in [5, 15] it returns
Response({"error": "You cannot assign a role lower than the workspace role"},
status=status.HTTP_400_BAD_REQUEST) so workspace admins cannot be demoted to
lower project roles; use the same Response and status.HTTP_400_BAD_REQUEST
pattern as the existing constraint.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cf28a5f8-c900-4b1f-af82-7a3d0cb9862b

📥 Commits

Reviewing files that changed from the base of the PR and between 9491bdb and a264f3a.

📒 Files selected for processing (1)
  • apps/api/plane/app/views/project/member.py

@sriramveeraghanta sriramveeraghanta merged commit 4c1bdd1 into preview May 5, 2026
20 of 22 checks passed
@sriramveeraghanta sriramveeraghanta deleted the fix/project-member-role-update-workspace-admin-subject branch May 5, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants