home / skills / yonatangross / orchestkit / input-validation

input-validation skill

/plugins/ork/skills/input-validation

This skill enforces server-side input validation and sanitization using Zod and Pydantic, reducing injections and ensuring safe, typed data.

npx playbooks add skill yonatangross/orchestkit --skill input-validation

Review the files below or copy the command above to add this skill to your agents.

Files (5)
SKILL.md
4.7 KB
---
name: input-validation
description: Input validation and sanitization patterns. Use when validating user input, preventing injection attacks, implementing allowlists, or sanitizing HTML/SQL/command inputs.
context: fork
agent: security-auditor
version: 2.0.0
tags: [security, validation, zod, pydantic, 2026]
allowed-tools:
  - Read
  - Grep
  - Glob
  - Write
  - Edit
author: OrchestKit
user-invocable: false
---

# Input Validation

Validate and sanitize all untrusted input using Zod v4 and Pydantic.

## Overview

- Processing user input
- Query parameters
- Form submissions
- API request bodies
- File uploads
- URL validation

## Core Principles

1. **Never trust user input**
2. **Validate on server-side** (client-side is UX only)
3. **Use allowlists** (not blocklists)
4. **Validate type, length, format, range**

## Quick Reference

### Zod v4 Schema

```typescript
import { z } from 'zod';

const UserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2).max(100),
  age: z.coerce.number().int().min(0).max(150),
  role: z.enum(['user', 'admin']).default('user'),
});

const result = UserSchema.safeParse(req.body);
if (!result.success) {
  return res.status(400).json({ errors: result.error.flatten() });
}
```

### Type Coercion (v4)

```typescript
// Query params come as strings - coerce to proper types
z.coerce.number()  // "123" → 123
z.coerce.boolean() // "true" → true
z.coerce.date()    // "2024-01-01" → Date
```

### Discriminated Unions

```typescript
const ShapeSchema = z.discriminatedUnion('type', [
  z.object({ type: z.literal('circle'), radius: z.number() }),
  z.object({ type: z.literal('rectangle'), width: z.number(), height: z.number() }),
]);
```

### Pydantic (Python)

```python
from pydantic import BaseModel, EmailStr, Field

class User(BaseModel):
    email: EmailStr
    name: str = Field(min_length=2, max_length=100)
    age: int = Field(ge=0, le=150)
```

## Anti-Patterns (FORBIDDEN)

```typescript
// ❌ NEVER rely on client-side validation only
if (formIsValid) submit();  // No server validation

// ❌ NEVER use blocklists
const blocked = ['password', 'secret'];  // Easy to miss fields

// ❌ NEVER trust Content-Type header
if (file.type === 'image/png') {...}  // Can be spoofed

// ❌ NEVER build queries with string concat
"SELECT * FROM users WHERE name = '" + name + "'"  // SQL injection

// ✅ ALWAYS validate server-side
const result = schema.safeParse(req.body);

// ✅ ALWAYS use allowlists
const allowed = ['name', 'email', 'createdAt'];

// ✅ ALWAYS validate file magic bytes
const isPng = buffer[0] === 0x89 && buffer[1] === 0x50;

// ✅ ALWAYS use parameterized queries
db.query('SELECT * FROM users WHERE name = ?', [name]);
```

## Key Decisions

| Decision | Recommendation |
|----------|----------------|
| Validation library | Zod (TS), Pydantic (Python) |
| Strategy | Allowlist over blocklist |
| Location | Server-side always |
| Error messages | Generic (don't leak info) |
| File validation | Check magic bytes, not just extension |

## Detailed Documentation

| Resource | Description |
|----------|-------------|
| [references/zod-v4-api.md](references/zod-v4-api.md) | Zod v4 API with coercion, transforms |
| [examples/validation-patterns.md](examples/validation-patterns.md) | Complete validation examples |
| [checklists/validation-checklist.md](checklists/validation-checklist.md) | Implementation checklist |
| [scripts/validation-schemas.ts](scripts/validation-schemas.ts) | Ready-to-use schema templates |

## Related Skills

- `owasp-top-10` - Injection prevention
- `auth-patterns` - User input in auth
- `type-safety-validation` - TypeScript patterns

## Capability Details

### schema-validation
**Keywords:** schema, validate, Zod, Pydantic, validation
**Solves:**
- Validate input against schemas
- Define validation rules declaratively
- Handle validation errors gracefully

### type-coercion
**Keywords:** coerce, coercion, type conversion, parse
**Solves:**
- Automatically convert input types
- Parse strings to numbers/dates
- Handle type mismatches

### allowlist-validation
**Keywords:** allowlist, whitelist, enum, literal, allowed values
**Solves:**
- Validate against allowed values
- Prevent injection attacks
- Restrict input to safe options

### html-sanitization
**Keywords:** sanitize, HTML, XSS, escape, DOMPurify
**Solves:**
- Sanitize HTML input safely
- Prevent XSS attacks
- Allow safe HTML subset

### file-validation
**Keywords:** file, upload, MIME type, file size, file type
**Solves:**
- Validate file uploads securely
- Check file content not just extension
- Enforce size limits

### error-formatting
**Keywords:** error, error message, validation error, user-friendly
**Solves:**
- Format validation errors for users
- Avoid exposing internal details
- Provide actionable error messages

Overview

This skill provides production-ready input validation and sanitization patterns for TypeScript and Python projects. It focuses on server-side validation, allowlists, type coercion, file validation, and safe error handling to prevent injection and XSS attacks. Use these patterns to standardize validation across APIs, forms, and file uploads.

How this skill works

Schemas define expected shapes and constraints using Zod (TypeScript) or Pydantic (Python). Incoming data is coerced to the right types, validated against allowlists and discriminated unions, and sanitized where needed (HTML, SQL, commands). File uploads are validated by magic bytes and size limits. Validation errors are normalized and returned with generic messages that avoid leaking internal details.

When to use it

  • Validating API request bodies, query params, and form submissions on the server
  • Enforcing allowlisted fields and values to prevent injection attacks
  • Coercing and parsing query string types (numbers, booleans, dates)
  • Sanitizing HTML input to prevent XSS and escaping user data in outputs
  • Validating uploaded files by magic bytes, MIME, and size limits

Best practices

  • Always validate on the server; client-side checks are for UX only
  • Prefer allowlists (allowed fields/values) instead of blocklists
  • Use Zod v4 for TypeScript and Pydantic for Python to declare schemas
  • Coerce string inputs to appropriate types for robust parsing
  • Validate file magic bytes and use parameterized queries for DB access
  • Return generic error messages and format validation errors for UX

Example use cases

  • API endpoint that safeParses a request body with Zod and rejects invalid payloads
  • Form handler that coerces query params to numbers/booleans and validates ranges
  • File upload service that checks magic bytes, max size, and allowed MIME families
  • Sanitizing user-generated HTML with a whitelist approach to prevent XSS
  • Discriminated union patterns for polymorphic payloads (e.g., different shape per type field)

FAQ

Should I rely on client-side validation?

No. Client-side validation improves UX but never replaces server-side checks.

When should I use allowlists versus blocklists?

Always use allowlists to explicitly accept only known safe fields and values; blocklists are error-prone and incomplete.