mirror of
https://github.com/makeplane/plane.git
synced 2026-07-09 20:10:06 +02:00
[WEB-7855] fix(security): prevent project invite email disclosure via unauthenticated GET (#9305)
ProjectJoinEndpoint.get() was AllowAny and used ProjectMemberInviteSerializer (fields = "__all__"), leaking the invitee's email and token to anyone who knew the workspace slug, project ID, and invite UUID (GHSA-2r58-hgv7-635q). Introduce ProjectMemberInvitePublicSerializer with an explicit safe field list that excludes `email` and `token`, and swap it in for the public GET endpoint. The full serializer is retained for authenticated admin viewsets. Co-authored-by: Plane AI <noreply@plane.so>
This commit is contained in:
@@ -35,6 +35,7 @@ from .project import (
|
||||
ProjectDetailSerializer,
|
||||
ProjectMemberSerializer,
|
||||
ProjectMemberInviteSerializer,
|
||||
ProjectMemberInvitePublicSerializer,
|
||||
ProjectIdentifierSerializer,
|
||||
ProjectLiteSerializer,
|
||||
ProjectMemberLiteSerializer,
|
||||
|
||||
@@ -203,6 +203,31 @@ class ProjectMemberInviteSerializer(BaseSerializer):
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class ProjectMemberInvitePublicSerializer(BaseSerializer):
|
||||
"""Safe read-only serializer for the public project invite GET endpoint.
|
||||
|
||||
Intentionally excludes ``email`` and ``token`` so that an unauthenticated
|
||||
caller cannot retrieve the invitee's email address or the acceptance token
|
||||
(GHSA-2r58-hgv7-635q).
|
||||
"""
|
||||
|
||||
project = ProjectLiteSerializer(read_only=True)
|
||||
workspace = WorkspaceLiteSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ProjectMemberInvite
|
||||
fields = [
|
||||
"id",
|
||||
"project",
|
||||
"workspace",
|
||||
"role",
|
||||
"message",
|
||||
"accepted",
|
||||
"responded_at",
|
||||
]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class ProjectIdentifierSerializer(BaseSerializer):
|
||||
class Meta:
|
||||
model = ProjectIdentifier
|
||||
|
||||
@@ -19,7 +19,10 @@ from rest_framework.permissions import AllowAny
|
||||
|
||||
# Module imports
|
||||
from .base import BaseViewSet, BaseAPIView
|
||||
from plane.app.serializers import ProjectMemberInviteSerializer
|
||||
from plane.app.serializers import (
|
||||
ProjectMemberInviteSerializer,
|
||||
ProjectMemberInvitePublicSerializer,
|
||||
)
|
||||
from plane.app.permissions import allow_permission, ROLE
|
||||
from plane.db.models import (
|
||||
ProjectMember,
|
||||
@@ -250,5 +253,5 @@ class ProjectJoinEndpoint(BaseAPIView):
|
||||
|
||||
def get(self, request, slug, project_id, pk):
|
||||
project_invitation = ProjectMemberInvite.objects.get(workspace__slug=slug, project_id=project_id, pk=pk)
|
||||
serializer = ProjectMemberInviteSerializer(project_invitation)
|
||||
serializer = ProjectMemberInvitePublicSerializer(project_invitation)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
||||
Reference in New Issue
Block a user