Skip to content

A.6 — Lock down /api/formSubmission GET and POST (PII + forgery) #270

@v-patel

Description

@v-patel

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:

  1. Privacy: leaks minor-aged-student activity logs to the public.
  2. 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

  • Anonymous GET/POST return 401.
  • Reader GET only returns submissions for their own students.
  • Reader POST only succeeds for their own students; otherwise 403.
  • Admin GET returns everything.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions