[WEB-7847] fix: enforce workspace membership on entity-search endpoint#9296
[WEB-7847] fix: enforce workspace membership on entity-search endpoint#9296mguptahub wants to merge 2 commits into
Conversation
…3-mqpc-3mhv) SearchEndpoint required authentication but did not verify the requesting user was a member of the queried workspace. Any authenticated Plane user could enumerate members across workspaces they don't belong to by guessing slugs. Add a WorkspaceMember guard at the top of get() — returns 403 if the user is not an active member of the target workspace. Brings OSS to parity with EE, which already had this protection via @can(WorkspacePermissions.VIEW). Co-authored-by: Plane AI <noreply@plane.so>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesSearch Permission Guard
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
|
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
| class SearchEndpoint(BaseAPIView): | ||
| def get(self, request, slug): | ||
| # Verify the requesting user is an active member of the target workspace. | ||
| # Without this guard any authenticated user can enumerate members of | ||
| # workspaces they do not belong to (GHSA-32q3-mqpc-3mhv). | ||
| if not WorkspaceMember.objects.filter( | ||
| member=request.user, | ||
| workspace__slug=slug, | ||
| is_active=True, | ||
| ).exists(): | ||
| return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN) |
There was a problem hiding this comment.
| class SearchEndpoint(BaseAPIView): | |
| def get(self, request, slug): | |
| # Verify the requesting user is an active member of the target workspace. | |
| # Without this guard any authenticated user can enumerate members of | |
| # workspaces they do not belong to (GHSA-32q3-mqpc-3mhv). | |
| if not WorkspaceMember.objects.filter( | |
| member=request.user, | |
| workspace__slug=slug, | |
| is_active=True, | |
| ).exists(): | |
| return Response({"error": "Forbidden"}, status=status.HTTP_403_FORBIDDEN) | |
| class SearchEndpoint(BaseAPIView): | |
| permission_classes = (WorkspaceUserPermission, ) | |
| def get(self, request, slug): |
Instead of doing inline, please use the existing permission class
@mguptahub
There was a problem hiding this comment.
Done. Swapped the inline check for permission_classes = (WorkspaceUserPermission,) on SearchEndpoint. WorkspaceUserPermission reads view.workspace_slug which resolves to self.kwargs.get("slug") — matching the URL kwarg — so the enforcement is identical, just in the right layer.
…UserPermission Use the existing WorkspaceUserPermission permission class on SearchEndpoint instead of a manual WorkspaceMember.objects.filter() guard inside the method body. Enforcement behaviour is unchanged (GHSA-32q3-mqpc-3mhv). Co-authored-by: Plane AI <noreply@plane.so>
Summary
SearchEndpoint(/workspaces/<slug>/entity-search/) required authentication but did not verify the requesting user was a member of the queried workspaceFix
Added a
WorkspaceMemberguard at the top ofSearchEndpoint.get()— returns403 Forbiddenif the requesting user is not an active member of the target workspace.The EE version already had this protection via
@can(WorkspacePermissions.VIEW). This brings OSS to parity.Files changed:
apps/api/plane/app/views/search/base.py(+10 lines)Test plan
/workspaces/<own-slug>/entity-search/→200 OKwith results/workspaces/<other-slug>/entity-search/for a workspace they don't belong to →403 Forbidden401 Unauthorized(unchanged, handled byBaseAPIView)Summary by CodeRabbit