CVE-2026-104955 Overview
Plane is an open-source project management tool used for issue tracking and team collaboration. CVE-2026-104955 is a privilege escalation vulnerability [CWE-269] affecting Plane versions prior to 1.4.0. A Project Member with role 15 can send a crafted PATCH request to the project-member update endpoint and promote a Project Guest (role 5) to Member without Project Admin approval. The flaw stems from role-update logic that only blocks assignments higher than the requester's role, allowing equal-role assignments to bypass governance controls. The issue is fixed in version 1.4.0.
Critical Impact
A regular Project Member can elevate Project Guests to Member status, bypassing Project Admin approval and granting unauthorized access to additional project capabilities.
Affected Products
- Plane (makeplane/plane) versions prior to 1.4.0
- Self-hosted Plane deployments exposing the workspace project-member API
- Plane instances with mixed Guest and Member role usage
Discovery Timeline
- 2026-10-05 - CVE-2026-104955 published to NVD
- 2026-10-07 - Last updated in NVD database
Technical Details for CVE-2026-104955
Vulnerability Analysis
The vulnerability resides in the project member update handler at apps/api/plane/app/views/project/member.py. The partial_update method accepts a PATCH request against /api/workspaces/{workspace_slug}/projects/{project_id}/members/{member_pk}/. The role validation logic fetched the workspace role of the target user rather than the requester. The authorization check then only rejected a new role strictly greater than that fetched role.
Because the check used the wrong principal and permitted equal-role assignments, a Project Member (role 15) could assign the Member role to a Project Guest (role 5). This bypassed the intended governance control requiring Project Admin approval for role promotions.
Root Cause
The root cause is improper privilege management [CWE-269]. The handler conflated the target user's workspace role with the requester's authority. Assigning an equal role was treated as safe, which is incorrect when the requester lacks administrative privileges. The fix separates target_workspace_role from requester_workspace_role and derives is_workspace_admin from the requester.
Attack Vector
An authenticated user with Project Member role (15) in the target workspace sends a PATCH request to the member endpoint, specifying the Guest user's primary key and setting the role field to 15 (Member). The API accepts the update and promotes the Guest without administrative approval. Exploitation requires low privileges and no user interaction.
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:
Source: GitHub Commit 4c1bdd1d
Detection Methods for CVE-2026-104955
Indicators of Compromise
- PATCH requests to /api/workspaces/{workspace_slug}/projects/{project_id}/members/{member_pk}/ originating from non-admin accounts
- Audit log entries showing Project Guest accounts (role 5) transitioning to Member (role 15) without a corresponding admin action
- Unexpected changes to project membership rosters performed outside administrative sessions
Detection Strategies
- Review Plane API access logs for PATCH operations against the project-member endpoint and correlate the requesting user's role with the resulting role change
- Baseline normal role-assignment behavior and alert on promotions initiated by non-admin principals
- Query the Plane database for ProjectMember role transitions and compare the actor to the project's admin list
Monitoring Recommendations
- Forward Plane application and reverse-proxy logs to a centralized log platform for retention and correlation
- Implement alerts on bulk or repeated role-change requests targeting Guest accounts within short time windows
- Monitor for anomalous API session activity from accounts that previously held only Member-level privileges
How to Mitigate CVE-2026-104955
Immediate Actions Required
- Upgrade Plane to version 1.4.0 or later across all self-hosted deployments
- Audit existing project memberships and revert any unauthorized Guest-to-Member promotions
- Rotate API tokens belonging to accounts suspected of exploiting the endpoint
Patch Information
The fix is included in Plane v1.4.0. The patch introduces a distinct requester_workspace_role lookup and bases administrative bypass checks on the requester rather than the target. See the GitHub Security Advisory GHSA-x63v-p7wc-47x4, the Pull Request #9014, and the v1.4.0 Release Notes for full details.
Workarounds
- Restrict access to the project-member update endpoint at the reverse proxy to administrative accounts until the upgrade is applied
- Temporarily limit Project Guest usage in sensitive workspaces to reduce the attack surface for role promotions
- Review and reduce the number of non-admin Project Members in workspaces that contain confidential projects
# Example: upgrade self-hosted Plane deployment to v1.4.0
git fetch --tags
git checkout v1.4.0
docker compose pull
docker compose up -d
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.