Bug Description
�iewer.bookings.updateWrongAssignmentReportStatus is gated only by �uthedProcedure (any authenticated user). The handler fetches the eamId from the report but never uses it to verify the caller is a member of that team before updating the report status.
Affected files
packages/trpc/server/routers/viewer/bookings/_router.tsx, line 149:
s updateWrongAssignmentReportStatus: authedProcedure // no team-membership guard .input(...) .mutation(...)
packages/trpc/server/routers/viewer/bookings/updateWrongAssignmentReportStatus.handler.ts, lines 25-39:
s const report = await repo.findTeamIdById(reportId); // teamId fetched // teamId is never compared to caller's memberships const updatedReport = await repo.updateStatus({ id: reportId, status, reviewedById: user.id, // updated unconditionally });
Failure scenario
- Attacker authenticates as any cal.com user.
- Calls �iewer.bookings.updateWrongAssignmentReportStatus { reportId: <any_id>, status: "DISMISSED" }.
- Handler updates the report without verifying the caller belongs to the report's team.
- Attacker silently dismisses wrong-assignment reports belonging to any team in the system.
- This corrupts audit and compliance workflows for organizations that rely on report review.
Fix
Add a membership check after fetching the report:
s const report = await repo.findTeamIdById(reportId); const membership = await prisma.membership.findFirst({ where: { userId: user.id, teamId: report.teamId, accepted: true }, }); if (!membership) throw new TRPCError({ code: "FORBIDDEN" });
Environment
cal.com main branch (2026-08-13).
Bug Description
�iewer.bookings.updateWrongAssignmentReportStatus is gated only by �uthedProcedure (any authenticated user). The handler fetches the eamId from the report but never uses it to verify the caller is a member of that team before updating the report status.
Affected files
packages/trpc/server/routers/viewer/bookings/_router.tsx, line 149:
s updateWrongAssignmentReportStatus: authedProcedure // no team-membership guard .input(...) .mutation(...)packages/trpc/server/routers/viewer/bookings/updateWrongAssignmentReportStatus.handler.ts, lines 25-39:
s const report = await repo.findTeamIdById(reportId); // teamId fetched // teamId is never compared to caller's memberships const updatedReport = await repo.updateStatus({ id: reportId, status, reviewedById: user.id, // updated unconditionally });Failure scenario
Fix
Add a membership check after fetching the report:
s const report = await repo.findTeamIdById(reportId); const membership = await prisma.membership.findFirst({ where: { userId: user.id, teamId: report.teamId, accepted: true }, }); if (!membership) throw new TRPCError({ code: "FORBIDDEN" });Environment
cal.com main branch (2026-08-13).