Skip to content

security: analytics charts endpoint leaks cross-workspace cycle and module dates via unscoped ID lookup #9601

Description

@harsh4vardhan

Bug Description

The advance analytics charts endpoint looks up Cycle and Module by bare ID with no workspace scope. An authenticated user in workspace A can read start_date and end_date from cycles and modules belonging to workspace B by passing foreign UUIDs in the query parameters.

Affected file

�pps/api/plane/app/views/analytic/project_analytics.py:

`python
cycle = Cycle.objects.filter(id=cycle_id).first() # line 196 - no workspace filter

...

module = Module.objects.filter(id=module_id).first() # line 208 - no workspace filter
`

The endpoint is protected by @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) which validates the caller's membership in the requested workspace. The CycleIssue query is correctly scoped via �ase_filters (which includes workspace__slug=slug), so it returns no data for foreign cycle IDs. But the bare Cycle.objects.filter(id=...) lookup succeeds for any cycle UUID in the database, and the response includes cycle.start_date and cycle.end_date directly in the chart metadata.

Failure scenario

  1. User in workspace A calls GET /workspaces/workspace-a/projects/<any_id>/advance-analytics-charts/?type=work-items&cycle_id=<UUID_from_workspace_B>.
  2. The permission check passes (user is a member of workspace A).
  3. Cycle.objects.filter(id=<UUID_from_workspace_B>).first() returns the foreign cycle object.
  4. start_date and end_date from workspace B's cycle are included in the API response.
  5. By iterating UUIDs, an attacker can enumerate cycle date ranges across all workspaces.

Fix

python cycle = Cycle.objects.filter(id=cycle_id, workspace__slug=slug).first() module = Module.objects.filter(id=module_id, workspace__slug=slug).first()

Environment

Plane develop branch (2026-08-13).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions