HighSecurityAuto-fixable

Missing Input Validation on API Route

A POST or PATCH API route spreads the raw request body into a database write without validating that fields exist, match expected types, or lie within expected ranges.

Typical error

Request body accepted without schema check

What this is

A generated API route that looks like:

export async function POST(req: Request) {
  const body = await req.json()
  const user = await db.user.create({ data: body })
  return Response.json(user)
}

Nothing stops the caller from including extra fields like isAdmin: true, role: 'owner', or credits: 999999. The database happily writes them.

Why AI tools ship this

"Spread the body" is the shortest code path that makes the endpoint work on the happy path. Validation is extra work the AI skips by default.

How to detect

Look for req.json() or await request.body being passed directly to db.*.create, db.*.update, or similar without any validation in between.

How to fix

Use Zod (or valibot) to define a schema for every API endpoint. Accept only what you declared.

import { z } from 'zod'
 
const CreateUserInput = z.object({
  email: z.string().email(),
  displayName: z.string().min(1).max(100),
})
 
export async function POST(req: Request) {
  const result = CreateUserInput.safeParse(await req.json())
  if (!result.success) {
    return new Response(
      JSON.stringify({ error: result.error.flatten() }),
      { status: 400 }
    )
  }
 
  const user = await db.user.create({
    data: {
      email: result.data.email,
      displayName: result.data.displayName,
      // explicit fields only, no spread
    },
  })
 
  return Response.json(user)
}

Never pattern data: { ...body }. Always name every column you are writing.

Commonly affected tools

Glossary

Is your app affected?

FinishKit checks for this finding and 50+ more across 8 dimensions of production readiness. Free during beta.

Scan your app