fix(analytics): scope Cycle and Module lookups by workspace slug to prevent cross-workspace data leak - #9608
Conversation
…t cross-workspace data leak The analytics charts endpoint accepts cycle_id and module_id as query params and fetches rows using only the bare primary key with no workspace constraint. A member of Workspace A can supply a cycle or module UUID from Workspace B and receive its start_date and end_date. Permission validation only confirms the caller is a member of the requesting workspace; it does not verify the supplied IDs belong to that workspace. Fix: add workspace__slug=self._workspace_slug to both filter calls so a foreign ID returns None, which the existing guard converts to an empty response. Fixes makeplane#9601 Signed-off-by: harsh4vardhan <hvardhan609@gmail.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe work-item completion chart now scopes cycle and module lookups to the selected workspace. This prevents cross-workspace objects from contributing date metadata to analytics responses. ChangesAnalytics workspace scoping
Estimated code review effort: 2 (Simple) | ~5 minutes Mergeability Score: ⚪ Minimal · up to This change scopes analytics lookups to the requested workspace, and no actionable merge-blocking risk remains beyond normal checks and review. Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
What
Add workspace__slug=self._workspace_slug to the Cycle and Module filter calls in the analytics charts endpoint.
Why
ProjectAdvanceAnalyticsStatsEndpoint and ProjectAdvanceAnalyticsChartEndpoint accept cycle_id and module_id as query params and look them up with only the primary key:
cycle = Cycle.objects.filter(id=cycle_id).first() # no workspace scope
module = Module.objects.filter(id=module_id).first() # no workspace scope
An authenticated member of Workspace A can supply a cycle or module UUID from Workspace B. Permission validation confirms the caller is a Workspace A member but does not validate that the supplied IDs belong to Workspace A. The response leaks Workspace B start_date and end_date.
How
before: cycle = Cycle.objects.filter(id=cycle_id).first()
after: cycle = Cycle.objects.filter(id=cycle_id, workspace__slug=self._workspace_slug).first()
before: module = Module.objects.filter(id=module_id).first()
after: module = Module.objects.filter(id=module_id, workspace__slug=self._workspace_slug).first()
The existing if cycle and cycle.start_date guards already return an empty response when the lookup returns None.
Closes #9601
harsh4vardhan
Summary by CodeRabbit