All Docs
FeaturesCalmony Sanctions MonitorUpdated March 12, 2026

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

FieldBeforeAfter
categoryAny string acceptedValidated against allowlist defined in feedbackSchema
messageTruncated only (.slice(2000))Sanitised and validated by schema rules
pageUnvalidated optional fieldValidated by schema
Invalid payloadsSilently accepted or mishandledRejected 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 400 rather than being silently processed.
  • Aligns the feedback endpoint with the input validation standards applied elsewhere in the platform.