From d90a8fd560cf94eca0bd62bb6617697daae998f8 Mon Sep 17 00:00:00 2001 From: janpeter visser Date: Sat, 25 Apr 2026 13:44:51 +0200 Subject: [PATCH] fix: PATCH /api/tasks/:id geeft 403 bij cross-user toegang Vervang productAccessFilter in de WHERE clause door een expliciete toegangscheck na het ophalen. findFirst haalt de taak op met product en members (gefilterd op auth.userId); daarna wordt eigenaarschap of teamlidmaatschap gecontroleerd en 403 teruggegeven bij geen toegang. Dit herstelt het onderscheid 404 (taak bestaat niet) vs 403 (taak bestaat maar geen toegang), zoals de beveiligingstest verwacht. Co-Authored-By: Claude Sonnet 4.6 --- app/api/tasks/[id]/route.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/app/api/tasks/[id]/route.ts b/app/api/tasks/[id]/route.ts index 796c0bb..250aeba 100644 --- a/app/api/tasks/[id]/route.ts +++ b/app/api/tasks/[id]/route.ts @@ -1,6 +1,5 @@ import { authenticateApiRequest } from '@/lib/api-auth' import { prisma } from '@/lib/prisma' -import { productAccessFilter } from '@/lib/product-access' import { z } from 'zod' const patchSchema = z @@ -27,12 +26,33 @@ export async function PATCH( const { id } = await params const task = await prisma.task.findFirst({ - where: { id, story: { product: productAccessFilter(auth.userId) } }, + where: { id }, + include: { + story: { + include: { + product: { + include: { + members: { + where: { user_id: auth.userId }, + select: { id: true }, + }, + }, + }, + }, + }, + }, }) if (!task) { return Response.json({ error: 'Taak niet gevonden' }, { status: 404 }) } + const hasAccess = + task.story.product.user_id === auth.userId || + (task.story.product.members?.length ?? 0) > 0 + if (!hasAccess) { + return Response.json({ error: 'Geen toegang' }, { status: 403 }) + } + const body = await request.json().catch(() => null) const parsed = patchSchema.safeParse(body) if (!parsed.success) {