Security: Cross-workspace survey data IDOR in allResultCount (missing workspaceId filter)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 3.1k
- Forks
- 194
- Avg merge
- 18m
- Merged PRs (30d)
- 3
Description
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,
});
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read src/server/trpc/routers/survey.ts around lines 110-133 and compare allResultCount with the workspace-scoped handlers in the same file. Then inspect the insights filterParams query for the survey case. Done means both endpoints restrict returned survey data to the current workspace, including result counts and field configurations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend-api-design, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100