A.6 — Lock down /api/formSubmission GET and POST (PII + forgery)
What's wrong
server/api/formSubmission/index.ts has no auth on either method.
- GET: anyone can list submissions filtered by
student, form, or formGroup → ties student names to form completions and timestamps.
- POST: anyone can create a submission for any
(form, student) pair, with no ownership check.
Why it matters
Two problems in one:
- Privacy: leaks minor-aged-student activity logs to the public.
- Integrity: lets an attacker stuff the raffle pool with fake completions for whichever student they want to win.
How to fix
const session = await requireSession(event)
if (method === 'GET') {
// scope to caller's own students unless they are admin
const isAdmin = !!(await prisma.admin.findUnique({ where: { userId: session.user.id } }))
if (!isAdmin) {
const ownStudents = await prisma.student.findMany({
where: { parentUserId: session.user.id },
select: { id: true },
})
where.student = { in: ownStudents.map(s => s.id) }
}
return await prisma.formSubmission.findMany({ where })
}
if (method === 'POST') {
const body = await readBody(event)
const studentId = Number(body.student)
// verify the caller owns this student (or is admin)
const student = await prisma.student.findFirst({
where: { id: studentId, parentUserId: session.user.id },
})
if (!student) throw createError({ statusCode: 403, statusMessage: 'Forbidden' })
// ... create submission ...
}
Files
server/api/formSubmission/index.ts (lines 5-37)
Severity
C (Critical).
Acceptance
A.6 — Lock down
/api/formSubmissionGET and POST (PII + forgery)What's wrong
server/api/formSubmission/index.tshas no auth on either method.student,form, orformGroup→ ties student names to form completions and timestamps.(form, student)pair, with no ownership check.Why it matters
Two problems in one:
How to fix
Files
server/api/formSubmission/index.ts(lines 5-37)Severity
C (Critical).
Acceptance