diff --git a/apps/api/plane/app/serializers/__init__.py b/apps/api/plane/app/serializers/__init__.py index 75cd35afc3d..6de6ee89870 100644 --- a/apps/api/plane/app/serializers/__init__.py +++ b/apps/api/plane/app/serializers/__init__.py @@ -35,6 +35,7 @@ ProjectDetailSerializer, ProjectMemberSerializer, ProjectMemberInviteSerializer, + ProjectMemberInvitePublicSerializer, ProjectIdentifierSerializer, ProjectLiteSerializer, ProjectMemberLiteSerializer, diff --git a/apps/api/plane/app/serializers/project.py b/apps/api/plane/app/serializers/project.py index 924c48fcfa3..aef296bc6c2 100644 --- a/apps/api/plane/app/serializers/project.py +++ b/apps/api/plane/app/serializers/project.py @@ -203,6 +203,31 @@ class Meta: 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 diff --git a/apps/api/plane/app/views/project/invite.py b/apps/api/plane/app/views/project/invite.py index 19d8c36bcf7..bc78c1a1c19 100644 --- a/apps/api/plane/app/views/project/invite.py +++ b/apps/api/plane/app/views/project/invite.py @@ -19,7 +19,10 @@ # 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 @@ def post(self, request, slug, project_id, pk): 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)