Security: Enforcing Input Validation on the Feedback API Endpoint
Security: Enforcing Input Validation on the Feedback API Endpoint
Release: v0.1.147 · Control: SEC-29 · Category: API Security
Background
The POST /api/feedback endpoint allows users to submit feedback messages from within the application. Prior to this release, the handler accepted the request body through a TypeScript type cast only:
// Before — no runtime validation
const body = await req.json() as { message: string; category: string; page?: string };
TypeScript type assertions are erased at compile time. At runtime, the shape and content of body was entirely unverified, meaning the endpoint trusted caller-supplied data unconditionally.
Vulnerabilities Addressed
1. Unvalidated category field
The category field was stored directly without being checked against any allowlist. A caller could submit an arbitrary string — including unexpected or malicious values — and the application would persist it without complaint.
2. Unsanitised message content
The message field was capped at 2,000 characters via a manual .slice(), but no sanitisation was applied. This left the field open to HTML injection or XSS payloads being stored and potentially rendered downstream.
3. Unused validation schema
A feedbackSchema was already defined in src/lib/validation.ts with the correct allowlist and sanitisation rules, but it was never imported or applied in the route handler — a gap between the intended security posture and the actual runtime behaviour.
What Changed
File: src/app/api/feedback/route.ts
The manual type cast has been replaced with a safeParse call against the existing feedbackSchema:
// After — Zod schema validation enforced
import { feedbackSchema } from '@/lib/validation';
const body = await req.json();
const result = feedbackSchema.safeParse(body);
if (!result.success) {
return Response.json({ error: 'Invalid request' }, { status: 400 });
}
// result.data is now safe to use
const { message, category, page } = result.data;
Effects of this change
| Field | Before | After |
|---|---|---|
category | Any string accepted | Validated against allowlist defined in feedbackSchema |
message | Truncated only (.slice(2000)) | Sanitised and validated by schema rules |
page | Unvalidated optional field | Validated by schema |
| Invalid payloads | Silently accepted or mishandled | Rejected with 400 Bad Request |
Why safeParse and Not parse
Zod's safeParse returns a result object rather than throwing on failure. This gives the route handler explicit control over the error response — returning a clean 400 — without relying on a top-level error boundary to catch and handle schema exceptions.
Single Source of Truth
By routing all feedback validation through feedbackSchema in src/lib/validation.ts, the validation rules are defined once and applied consistently. Any future changes to allowed categories or message constraints need to be made in a single location.
Impact
- No changes to the public API contract — valid, well-formed requests are unaffected.
- Malformed or potentially malicious requests now receive an explicit
400rather than being silently processed. - Aligns the feedback endpoint with the input validation standards applied elsewhere in the platform.