Summary
The allResultCount endpoint in the survey router returns result counts from ALL surveys across ALL workspaces, because the handler doesn't use the workspaceId from workspaceProcedure.
Details
File: src/server/trpc/routers/survey.ts lines 110-133
allResultCount: workspaceProcedure
.output(z.record(z.string(), z.number()))
.query(async () => { // ← No input destructuring, workspaceId unused
const res = await prisma.surveyResult.groupBy({
by: ['surveyId'],
_count: true, // ← No workspace filter!
});
return res.reduce<Record<string, number>>((prev, item) => {
if (item.surveyId) { prev[item.surveyId] = item._count; }
return prev;
}, {});
}),
Secure comparison (same file, line 43-48):
all: workspaceProcedure.query(async ({ input }) => {
const { workspaceId } = input; // ✓ workspaceId destructured
return prisma.survey.findMany({
where: { workspaceId }, // ✓ Filtered by workspace
});
}),
Every other handler in the file (lines 43, 73, 153, 365, 393, 440) destructures workspaceId and uses it in Prisma queries. allResultCount is the only one that doesn't.
Similarly, the insights filterParams endpoint queries prisma.survey.findFirst({ where: { id: insightId } }) without workspaceId when insightType === 'survey'.
Impact
Any authenticated user can enumerate survey result counts and survey field configurations across all workspaces.
Recommended Fix
.query(async ({ input }) => {
const { workspaceId } = input;
const res = await prisma.surveyResult.groupBy({
by: ['surveyId'],
where: { survey: { workspaceId } },
_count: true,
});
Summary
The
allResultCountendpoint in the survey router returns result counts from ALL surveys across ALL workspaces, because the handler doesn't use theworkspaceIdfromworkspaceProcedure.Details
File:
src/server/trpc/routers/survey.tslines 110-133Secure comparison (same file, line 43-48):
Every other handler in the file (lines 43, 73, 153, 365, 393, 440) destructures
workspaceIdand uses it in Prisma queries.allResultCountis the only one that doesn't.Similarly, the insights
filterParamsendpoint queriesprisma.survey.findFirst({ where: { id: insightId } })without workspaceId wheninsightType === 'survey'.Impact
Any authenticated user can enumerate survey result counts and survey field configurations across all workspaces.
Recommended Fix