# Validation runs before database writes

- **Pattern:** `ab-000277` (`ai-slop-security-theater.unenforced-validation.validation-runs-before-db-write`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000277
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000277)

## Why it matters

Calling `OrderSchema.parse(body)` after `prisma.order.create({ data: body })` already ran is not validation — it's an audit log that arrives after the crime. The bad data is committed to the database whether the parse throws or not. CWE-696 (Incorrect Behavior Order) captures this: the side effect precedes the safety check. An attacker who sends a malformed payload wins regardless of the parse result, because the DB write already succeeded.

## Severity rationale

High because validating after the write means every mutation executes with unvalidated input — the check fires after the attack surface is already exploited.

## Remediation

Move the parse call to the first statement after `req.json()`. Validation must throw before any `prisma.*` call is reachable.

```ts
// Bad: write happens before validation
export async function POST(req: Request) {
  const body = await req.json()
  const order = await prisma.order.create({ data: body })  // unvalidated write
  OrderSchema.parse(body)  // too late — commit already happened
  return Response.json(order)
}

// Good: validate first, then write
export async function POST(req: Request) {
  const body = await req.json()
  const data = OrderSchema.parse(body)  // throws before any DB interaction
  const order = await prisma.order.create({ data })
  return Response.json(order)
}
```

## Detection

- **ID:** `validation-runs-before-db-write`
- **Severity:** `high`
- **What to look for:** For mutating handlers that DO have a validation invocation, before evaluating, extract and quote the validation call line and the database write line. Verify the validation call appears BEFORE the database write in the function body's execution order. Count all handlers where validation exists but happens AFTER the write OR validation only validates a subset of the body that doesn't overlap with what's written.
- **Pass criteria:** 100% of mutating handlers with validation perform validation BEFORE the database write. Report: "X handlers with validation, Y validate-before-write, 0 validate-after-write."
- **Fail criteria:** At least 1 handler validates input AFTER writing to the database.
- **Skip (N/A) when:** Project has 0 mutating handlers OR no mutating handler invokes validation.
- **Detail on fail:** `"1 handler validates after DB write: app/api/orders/route.ts POST writes to prisma.order.create then calls OrderSchema.parse(body) — the write happens with unvalidated data"`
- **Remediation:** Validation after the write is meaningless — the bad data is already in the database. Reorder the calls:

  ```ts
  // Bad: write happens before validation
  export async function POST(req: Request) {
    const body = await req.json()
    const order = await prisma.order.create({ data: body })  // unvalidated
    OrderSchema.parse(body)  // too late
    return Response.json(order)
  }

  // Good: validate first
  export async function POST(req: Request) {
    const body = await req.json()
    const data = OrderSchema.parse(body)  // throws before DB write
    const order = await prisma.order.create({ data })
    return Response.json(order)
  }
  ```

## External references

- cwe CWE-20
- cwe CWE-696
- owasp A03

Taxons: placeholder-hygiene, injection-and-input-trust

HTML version: https://auditbuffet.com/patterns/ab-000277
