Files
gruperly/.agents/skills/zod/references/schema-string-validations.md
2026-09-04 16:49:24 -03:00

2.7 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
Apply String Validations at Schema Definition CRITICAL Unvalidated strings allow SQL injection, XSS, and malformed data; validating at schema level catches issues at the boundary 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):

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: '<script>alert("XSS")</script>'.repeat(100000),  // XSS + huge
  website: 'javascript:void(0)',  // Dangerous URL
})

Correct (string validations applied):

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:

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