Server-side validation mirrors client-side; crafted POST returns 400 not 500
Why it matters
Client-side validation is advisory — any attacker with curl can bypass it entirely. Without server-side enforcement on every field, a crafted POST with a missing title or malformed email doesn't get rejected at 400; it either crashes the handler with a 500 (leaking stack traces) or silently inserts garbage into your database. OWASP A03 (Injection) and CWE-20 (Improper Input Validation) both call this out as a critical failure mode: the server is the only trust boundary that matters.
Severity rationale
Critical because client-side bypasses are trivial and unvalidated inputs can cause 500 errors, crash handlers, or corrupt the database directly.
Remediation
Add a Zod schema in your API route and call .parse() before touching the database. Any ZodError returns a structured 400; all other errors stay as 500. In app/api/listings/submit/route.ts:
import { z } from 'zod'
const submissionSchema = z.object({
title: z.string().min(10).max(200),
description: z.string().min(50).max(5000),
contactEmail: z.string().email(),
category: z.string().min(1)
})
export async function POST(req: Request) {
const body = await req.json()
const result = submissionSchema.safeParse(body)
if (!result.success) {
return Response.json({ error: 'Validation failed', issues: result.error.issues }, { status: 400 })
}
// proceed with result.data
}
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the User Submissions & Moderation Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-20 — Improper Input Validation
- owasp:2021 · A03 — Injection
Taxons
History
- 2026-04-18·v1.0.0·Initial import from directory-submissions-moderation·automated