Form Validation & Security Guide
A comprehensive template for implementing defence-in-depth form security in React and Next.js applications. Covers frontend validation, XSS sanitization, server-side re-validation, and CORS configuration.
Paste into your AI chat
Copy the entire guide as markdown to use as context in Cursor, Claude, ChatGPT, or any AI tool.
Defence-in-Depth Approach
Four layers of protection for your forms.
Frontend Validation
Zod schemas for real-time feedback
XSS Sanitization
Strip malicious content before submission
API Validation
Server-side re-validation (never trust client)
CORS Configuration
Restrict allowed origins
Dependencies
Install the required packages for validation and sanitization.
Frontend Validation (Zod Schemas)
Create type-safe validation schemas that run in the browser for instant feedback.
XSS Sanitization
Strip malicious HTML/script content from user inputs before processing.
React Form Component
A complete form component with real-time validation and sanitization on submit.
API Endpoint (Server-Side)
Never trust the client. Re-validate and sanitize everything server-side.
CORS Configuration
Restrict which domains can make requests to your API.
Validation Rules Quick Reference
| Field Type | Validation Rules |
|---|---|
| Name | 2-100 chars, letters/spaces/hyphens/apostrophes only |
| Valid format, max 254 chars, auto-lowercase | |
| UK Phone | 07xxx (11 digits), +447xxx (12 digits), or landline |
| Message | 10-2000 chars |
| URL | Valid URL format with protocol |
| Dropdown | Must be one of allowed values (z.enum()) |
| Checkbox | Boolean, refine() for required agreement |
| Array | z.array() with .min(1) for required selections |
Common Patterns
Reusable Zod patterns for typical form fields.
Optional Fields with Empty String Fallback
comments: z
.string()
.max(2000, 'Comments must be less than 2000 characters')
.optional()
.or(z.literal('')),Enum Validation
subject: z
.enum(['maths', 'english', 'science'], {
message: 'Subject must be maths, english, or science',
}),Numeric Validation
results: z.object({
score: z.number().int().min(0).max(100),
totalQuestions: z.number().int().min(1).max(100),
}),Conditional Validation
phone: z
.string()
.max(20)
.refine(
(val) => !val || validateUKPhone(val),
'Please enter a valid UK phone number'
)
.optional()
.or(z.literal('')),Security Checklist
Use this checklist to verify your implementation is complete.
Frontend
- Install zod and xss packages
- Create validation schemas for all forms
- Implement real-time field validation on blur/change
- Sanitize all string inputs before submission
- Display user-friendly error messages
- Disable submit button during submission
API / Backend
- Re-validate all inputs server-side (never trust client)
- Sanitize all inputs before processing/storing
- Configure CORS to whitelist allowed origins only
- Return structured error responses with field-level errors
- Log errors for monitoring (don't expose stack traces)
- Use HTTPS in production
Want the full guide as context for your AI coding assistant?