agentsclimarketplace

Input validation guide

Skill VersoXBT/claude-initial-setup/skills/security/input-validation-guide

75 skills, 14 agents, 15 commands for Claude Code. Plug-and-play starter kit covering TypeScript, Python, Go, Rust, React, Next.js, FastAPI, Django, Docker, CI/CD, security, testing, and more. Cross-AI support for Cursor, Copilot, and Codex.

Install
npx -y skills add VersoXBT/claude-initial-setup --skill input-validation-guide

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Validate and sanitize all user input using schema validation libraries. Activate whenever the user writes form handlers, API endpoints, request parsers, data processing functions, or any code that accepts external input. Also activate when the user asks about validation libraries like Zod, Joi, or Pydantic, or discusses input sanitization.

SKILL.md

7.7 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it

Input Validation Guide

Validate all external input at system boundaries using schema validation libraries. Reject invalid data early with clear error messages. Never trust client-side validation as the sole defense.

When to Use

  • Writing API endpoint handlers that accept request bodies, query params, or path params
  • Building form validation logic (server-side)
  • Processing data from external APIs or file uploads
  • Parsing configuration files or environment variables
  • Any function that receives data from outside the trust boundary

Core Patterns

Zod (TypeScript)

The standard for TypeScript schema validation. Parse, don't validate.

import { z } from 'zod';

// Define schemas as the source of truth
const CreateUserSchema = z.object({
  email: z.string().email('Invalid email format'),
  name: z.string().min(1, 'Name required').max(100),
  age: z.number().int().min(13, 'Must be 13 or older').max(150),
  role: z.enum(['user', 'admin', 'moderator']).default('user'),
  website: z.string().url().optional(),
});

// Infer TypeScript types from schemas
type CreateUserInput = z.infer<typeof CreateUserSchema>;

// Parse at the boundary, use typed data internally
app.post('/api/users', async (req, res) => {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({
      error: 'Validation failed',
      issues: result.error.issues.map(i => ({
        field: i.path.join('.'),
        message: i.message,
      })),
    });
  }
  // result.data is fully typed as CreateUserInput
  const user = await createUser(result.data);
  res.json(user);
});

Advanced Zod patterns for complex validation:

// Transform and refine
const SearchParamsSchema = z.object({
  page: z.coerce.number().int().min(1).default(1),
  limit: z.coerce.number().int().min(1).max(100).default(20),
  sort: z.enum(['name', 'date', 'relevance']).default('relevance'),
  q: z.string().trim().min(1).max(200).optional(),
});

// Discriminated unions for type-safe variants
const PaymentSchema = z.discriminatedUnion('method', [
  z.object({
    method: z.literal('card'),
    cardNumber: z.string().regex(/^\d{16}$/),
    expiry: z.string().regex(/^\d{2}\/\d{2}$/),
    cvv: z.string().regex(/^\d{3,4}$/),
  }),
  z.object({
    method: z.literal('bank_transfer'),
    accountNumber: z.string().min(8).max(20),
    routingNumber: z.string().length(9),
  }),
]);

// Custom refinements with cross-field validation
const DateRangeSchema = z.object({
  startDate: z.coerce.date(),
  endDate: z.coerce.date(),
}).refine(
  data => data.endDate > data.startDate,
  { message: 'End date must be after start date', path: ['endDate'] }
);

Pydantic (Python)

The standard for Python data validation using type annotations.

from pydantic import BaseModel, Field, field_validator, EmailStr
from datetime import date
from enum import Enum

class UserRole(str, Enum):
    USER = "user"
    ADMIN = "admin"
    MODERATOR = "moderator"

class CreateUserRequest(BaseModel):
    email: EmailStr
    name: str = Field(min_length=1, max_length=100)
    age: int = Field(ge=13, le=150)
    role: UserRole = UserRole.USER
    website: str | None = None

    @field_validator("name")
    @classmethod
    def name_must_not_be_empty(cls, v: str) -> str:
        stripped = v.strip()
        if not stripped:
            raise ValueError("Name cannot be blank")
        return stripped

# FastAPI integration - validation is automatic
@app.post("/api/users")
async def create_user(data: CreateUserRequest):
    # data is already validated and typed
    return await save_user(data)

Allowlists vs Denylists

Always prefer allowlists. Denylists are inherently incomplete.

// WRONG: Denylist approach - always has gaps
function sanitizeFilename(name: string): string {
  return name.replace(/[<>:"/\\|?*]/g, ''); // What about null bytes? Unicode tricks?
}

// CORRECT: Allowlist approach - only permit known-good characters
function sanitizeFilename(name: string): string {
  const sanitized = name.replace(/[^a-zA-Z0-9._-]/g, '');
  if (!sanitized || sanitized.startsWith('.')) {
    throw new Error('Invalid filename');
  }
  return sanitized;
}

// CORRECT: Allowlist for content types
const ALLOWED_TYPES = new Set(['image/jpeg', 'image/png', 'image/webp', 'application/pdf']);
function validateContentType(type: string): boolean {
  return ALLOWED_TYPES.has(type);
}

Type Coercion Attack Prevention

Prevent attacks that exploit JavaScript's loose type coercion.

// WRONG: Vulnerable to type coercion
app.get('/api/users', (req, res) => {
  // req.query.admin could be "true" (string), true (if parsed), or ["true"] (array)
  if (req.query.admin == true) { // Loose equality - dangerous
    return getAdminData();
  }
});

// CORRECT: Strict parsing with Zod
const QuerySchema = z.object({
  admin: z.enum(['true', 'false']).transform(v => v === 'true').optional(),
  id: z.coerce.number().int().positive(), // Explicit coercion
});

app.get('/api/users', (req, res) => {
  const query = QuerySchema.parse(req.query);
  // query.admin is boolean | undefined, query.id is number
});

// WRONG: JSON.parse without validation
const config = JSON.parse(userInput); // Could be any type

// CORRECT: Parse then validate
const rawData = JSON.parse(userInput);
const config = ConfigSchema.parse(rawData);

Sanitization for Specific Contexts

Apply context-appropriate sanitization after validation.

import DOMPurify from 'dompurify';
import sqlstring from 'sqlstring';

// HTML content: strip dangerous tags
function sanitizeHtml(input: string): string {
  return DOMPurify.sanitize(input, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'li'],
    ALLOWED_ATTR: [],
  });
}

// Path traversal prevention
function safePath(basedir: string, userPath: string): string {
  const resolved = path.resolve(basedir, userPath);
  if (!resolved.startsWith(basedir)) {
    throw new Error('Path traversal detected');
  }
  return resolved;
}

Anti-Patterns

  • Relying solely on client-side validation (easily bypassed)
  • Using denylists instead of allowlists for filtering
  • Validating deep inside business logic instead of at the boundary
  • Using loose equality (==) instead of strict equality (===) in JavaScript
  • Trusting Content-Type headers without verifying actual content
  • Silently coercing invalid data instead of rejecting it
  • Writing custom regex for email, URL, or date validation instead of using library validators
  • Catching validation errors and returning generic "Bad Request" without field-level detail

Quick Reference

LanguageLibraryKey Pattern
TypeScriptZodschema.safeParse(input) returns { success, data, error }
TypeScriptJoischema.validate(input) returns { value, error }
PythonPydanticClass-based models with type annotations
GovalidatorStruct tags: validate:"required,email"
PrincipleRule
Validate earlyAt system boundaries, not deep in business logic
AllowlistPermit known-good, reject everything else
Parse, don't validateTransform raw input into typed domain objects
Fail loudlyReturn specific field-level error messages
Never trust clientServer-side validation is mandatory

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most quality gates skills give in ~1.8k tokens

Counted across 1,195 of the 2,094 authors here whose files we hold, read 2026-08-07

  • Read the output and check the exit codein 54 of 1195, across 14 files
  • Verify requirements using a line-by-line checklistin 53 of 1195, across 12 files
  • Identify the verification command proving the claimin 51 of 1195, across 12 files
  • Run the full verification commandin 50 of 1195, across 11 files
  • Verify output confirms the claimin 49 of 1195, across 12 files
  • Check version control diff after agent delegationin 46 of 1195, across 6 files
  • State claim with evidencein 44 of 1195, across 4 files
  • Run the test suitein 33 of 1195, across 26 files
  • Keep state in memory by defaultin 27 of 1195, across 6 files
  • Make prototype runnable with one commandin 26 of 1195, across 5 files
  • Produce a verification reportin 25 of 1195, across 14 files
  • Detect the package manager from lockfilesin 24 of 1195, across 5 files

Said here and by no other author read

  • reject invalid data early with clear error messages
  • infer types from validation schemas
  • prefer allowlists over denylists
  • parse input instead of manually validating
  • prevent type coercion attacks
  • apply context-appropriate sanitization after validation

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,984. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.