Skip to main content
Vulnerability Database/CVE-2026-105632

CVE-2026-105632: Plane GraphQL Privilege Escalation

CVE-2026-105632 is a privilege escalation flaw in Plane that allows workspace members to gain unauthorized access to private projects and modify confidential data. This article covers the technical details, affected versions, security impact, and mitigation strategies.

Published:

CVE-2026-105632 Overview

CVE-2026-105632 is a broken access control vulnerability [CWE-284] in Plane, an open-source project management platform. Versions prior to 1.4.0 expose a GraphQL joinProject mutation that fails to validate project-level visibility. Any authenticated workspace member can invoke the mutation to add themselves to any project within the workspace, including projects configured as network=0 (secret or private). The resolver only verifies workspace-level membership and role, bypassing the per-project tenant boundary. Successful exploitation grants the attacker a full Member role with read and write access to confidential data. The issue is fixed in Plane 1.4.0.

Critical Impact

A low-privilege workspace member can join any private project in the workspace and read or modify sensitive data without invitation.

Affected Products

  • Plane (makeplane/plane) all versions prior to 1.4.0
  • Self-hosted Plane deployments exposing the GraphQL API
  • Plane Cloud instances on vulnerable releases

Discovery Timeline

Technical Details for CVE-2026-105632

Vulnerability Analysis

Plane models tenant isolation at two layers: the workspace and the project. Projects carry a network attribute that determines visibility, where network=0 denotes a secret project restricted to invited members. The GraphQL joinProject mutation was designed to let workspace members opt into projects they already have permission to view. The resolver authorized the request based only on the caller's workspace membership and role, never consulting the target project's network value or invitation state. As a result, the project-level access boundary collapsed inside the workspace trust zone. An attacker who held any workspace role could enumerate project IDs and submit mutations to join them, inheriting the Member role with read and write permissions.

Root Cause

The root cause is missing authorization logic in the UserProjectInvitationsViewset and the GraphQL resolver backing joinProject. Supplied project_ids were trusted directly, so UUIDs referencing secret projects, or even projects in other workspaces, were used in ProjectMember queries without being filtered against a workspace-scoped, network-validated queryset. The code treated workspace membership as sufficient authorization for project membership, violating the principle of least privilege [CWE-284].

Attack Vector

Exploitation requires authenticated access as any workspace member and network reachability to the Plane GraphQL endpoint. The attacker submits a joinProject mutation with the UUID of a target private project. The server adds the attacker as an active ProjectMember and returns success. The attacker then reads issues, cycles, modules, documents, and attachments in that project, and can modify or delete content.

python
        workspace_role = workspace_member.role
        workspace = workspace_member.workspace

+        # Use the workspace-scoped, network-validated project IDs only.
+        # Raw project_ids may contain UUIDs from other workspaces; those are
+        # absent from the `projects` queryset and therefore bypass the SECRET
+        # network check above (GHSA-45hc-q4mw-jhxm).
+        validated_project_ids = [str(p.id) for p in projects]
+
        # If the user was already part of workspace
-        _ = ProjectMember.objects.filter(workspace__slug=slug, project_id__in=project_ids, member=request.user).update(
-            is_active=True
-        )
+        _ = ProjectMember.objects.filter(
+            workspace__slug=slug, project_id__in=validated_project_ids, member=request.user
+        ).update(is_active=True)

        ProjectMember.objects.bulk_create(
            [

Source: Plane commit e1ef420. The patch replaces the raw project_ids input with validated_project_ids, which contains only IDs from the projects queryset already filtered by workspace and network scope.

Detection Methods for CVE-2026-105632

Indicators of Compromise

  • GraphQL requests containing the joinProject mutation originating from users who were not previously listed as invitees of the target project.
  • Unexpected ProjectMember database rows created for network=0 projects, especially where the created_by and member fields reference the same low-privilege workspace user.
  • Spikes in UserProjectInvitationsViewset POST traffic targeting multiple project UUIDs from a single session.

Detection Strategies

  • Audit ProjectMember records created before upgrading to 1.4.0 and reconcile them against invitation history for private projects.
  • Correlate web server access logs with Plane application logs to identify workspace members who gained access to secret projects without an issued invitation.
  • Hunt for repeated project enumeration patterns, such as sequential or scripted mutations referencing many project UUIDs in a short window.

Monitoring Recommendations

  • Alert on new ProjectMember entries where the target project has network=0 and no corresponding ProjectInvite record exists.
  • Forward Plane API and database audit logs to a centralized analytics platform for retention and query across the exposure window.
  • Monitor GraphQL endpoint traffic for anomalous mutation volume per authenticated session.

How to Mitigate CVE-2026-105632

Immediate Actions Required

  • Upgrade all Plane deployments to version 1.4.0 or later without delay.
  • Review every private (network=0) project for unexpected members and remove unauthorized ProjectMember records.
  • Rotate credentials, API tokens, and any secrets stored in issues, documents, or attachments of exposed private projects.
  • Notify project owners of workspaces that contained confidential data about potential unauthorized access.

Patch Information

The fix is included in Plane v1.4.0 and introduced via Pull Request #9333 and commit e1ef420. The resolver now constructs validated_project_ids from a queryset that enforces both workspace scope and project network visibility, preventing raw caller-supplied UUIDs from bypassing the SECRET project check. Full remediation details are available in GHSA-45hc-q4mw-jhxm.

Workarounds

  • If immediate upgrade is not possible, restrict access to the Plane GraphQL endpoint using a reverse proxy or Web Application Firewall rule that blocks the joinProject mutation.
  • Temporarily reduce workspace membership to trusted users only, since any workspace member can exploit the flaw.
  • Move highly sensitive projects to a separate workspace with a limited member roster until the patch is applied.
bash
# Example: upgrade a self-hosted Plane deployment to the patched release
git fetch --tags
git checkout v1.4.0
docker compose -f docker-compose.yml pull
docker compose -f docker-compose.yml up -d

# Verify the running version
docker compose exec api python manage.py --version

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.