--- title: Apply String Validations at Schema Definition impact: CRITICAL impactDescription: Unvalidated strings allow SQL injection, XSS, and malformed data; validating at schema level catches issues at the boundary tags: schema, string, validation, security --- ## Apply String Validations at Schema Definition Plain `z.string()` accepts any string including empty strings, extremely long strings, and malicious content. Apply constraints like `min()`, `max()`, `email()`, `url()`, or `regex()` at schema definition to reject invalid data at the boundary. **Incorrect (no string validations):** ```typescript import { z } from 'zod' const commentSchema = z.object({ author: z.string(), // Empty string passes email: z.string(), // "not-an-email" passes content: z.string(), // 10MB string passes, script tags pass website: z.string().optional(), // "javascript:alert(1)" passes }) // All of these pass validation commentSchema.parse({ author: '', // Empty - who wrote this? email: 'invalid', // Not a real email content: ''.repeat(100000), // XSS + huge website: 'javascript:void(0)', // Dangerous URL }) ``` **Correct (string validations applied):** ```typescript import { z } from 'zod' const commentSchema = z.object({ author: z.string() .min(1, 'Author is required') .max(100, 'Author name too long'), email: z.string() .email('Invalid email address'), content: z.string() .min(1, 'Comment cannot be empty') .max(5000, 'Comment too long'), website: z.string() .url('Invalid URL') .refine( url => url.startsWith('http://') || url.startsWith('https://'), 'Only http/https URLs allowed' ) .optional(), }) // Invalid data is rejected commentSchema.parse({ author: '', email: 'invalid', content: '', }) // ZodError with all violations listed ``` **Common string validations:** ```typescript z.string().min(1) // Non-empty (most common need) z.string().max(255) // Database varchar limit z.string().length(36) // Exact length (UUIDs) z.string().email() // Email format z.string().url() // URL format z.string().uuid() // UUID format z.string().cuid() // CUID format z.string().regex(/^[a-z0-9-]+$/) // Custom pattern (slugs) z.string().startsWith('https://') // Prefix check z.string().endsWith('.pdf') // Suffix check z.string().includes('@') // Contains check z.string().trim() // Strips whitespace (transform) z.string().toLowerCase() // Normalizes case (transform) ``` **When NOT to use this pattern:** - When accepting arbitrary user content for display only (sanitize on output instead) - When building a passthrough/proxy that shouldn't validate content Reference: [Zod API - Strings](https://zod.dev/api#strings)