Guidance on input validation and security auditing for web applications, covering common injection risks, audit checklist, automated audit example, and practical mitigations for Node Express apps.
In this lesson we cover input validation — the checks and protections applied to any data that users (or automated clients) supply to your application. Robust input validation reduces the attack surface for SQL/NoSQL injection, command injection, XSS, path traversal, XML External Entity (XXE) attacks, and other common vectors.Below we outline what to look for in an audit, demonstrate an automated audit run, and provide practical mitigations and patterns you can apply immediately.
Treat all external inputs as untrusted. Validate types, lengths, allowed values, and apply context-appropriate encoding before using data in queries, file operations, or rendered HTML.
Inputs arrive via HTML forms, APIs, file uploads, headers, query strings, and other external interfaces. Even if no human attacker is targeting your app, automated scanners and bots continuously probe services for weaknesses.The classic “Little Bobby Tables” example shows how untrusted input interpolated into a SQL statement can cause data loss (SQL injection). Any time you build queries, shell commands, file paths, or HTML using external data, assume the input could be malicious and take steps to validate, sanitize, or parameterize it.For example, avoid building SQL like:
Copy
SELECT * FROM users WHERE username = '...user input...' ;
An attacker-controlled username like:
Copy
'; DROP TABLE students; --
could terminate and append destructive SQL. Use parameterized queries and strong validation instead.
Checklist of common input validation and related issues:
SQL injection: concatenation of raw inputs into SQL, unsanitized dynamic queries, unsafe stored procedure use.
NoSQL injection (MongoDB): unvalidated operator expressions (e.g., $where) or executing JavaScript in queries.
Command injection: passing unsanitized input to shell commands or child processes.
Cross-site scripting (XSS): missing output encoding or HTML sanitization for user content.
XXE (XML External Entity): insecure XML parsing that allows external entity resolution.
Path traversal: insufficient normalization/validation of file paths (../ attacks).
Request validation gaps: missing body-size limits, parameter pollution, lack of typed validation, or missing required fields.
Create a validation matrix mapping every endpoint to the protections applied (parameterized queries, schema validation, file handling constraints, rate limits, body-size limits, etc.). This helps prioritize fixes and ensures consistent coverage across routes.
Here is an example interactive session with an auditing assistant that generates a comprehensive input validation audit and writes it to the repository.Example CLI startup:
Copy
◉ jeremy@MACSTUDIO Express-login-demo % claude* Welcome to Claude Code!/help for help, /status for your current setupcwd: /Users/jeremy/Repos/Claude Code Course/Express-login-demo> Try "fix typecheck errors"? for shortcuts
The assistant produces a detailed Markdown audit at audits/INPUT_VALIDATION_SECURITY_REPORT.md. Typical contents include a risk score, critical findings, proof-of-concept examples (for owned systems only), and targeted remediation steps.
(The following is a consolidated, edited excerpt from a generated audit report.)
Copy
**Application:** Express Login Demo **Audit Date:** 2025-08-20 **Auditor:** Claude Code **Overall Risk Score:** 6/10 (Medium-High)## Executive SummaryThis security audit analyzed the Express.js login application for input validation vulnerabilities across all endpoints and data processing functions. The application demonstrates good foundational security practices with parameterized queries and [express-validator](https://express-validator.github.io/docs/) usage, but has critical gaps in security controls that create notable risk.**Key Findings**- ✅ SQL Injection protection implemented correctly (parameterized queries)- ✅ Input validation present ([express-validator](https://express-validator.github.io/docs/))- ❌ Missing rate limiting on authentication endpoints — critical- ❌ No request size limits — DoS through memory exhaustion possible- ❌ Weak JWT secret configuration in production- ❌ Incomplete input sanitization for some outputs- ❌ Missing security headers in responses
CWE: CWE-307 (Improper Restriction of Excessive Authentication Attempts)
Risk: Without throttling on endpoints like /api/auth/login, attackers can brute-force credentials or overload the endpoint.
Exploitability (example brute-force loop — do not run against third-party systems):
Copy
# Brute force attack example (do not run against third-party systems)for i in {1..1000}; do curl -s -X POST http://localhost:3000/api/auth/login \ -H "Content-Type: application/json" \ -d "{\"email\":\"test@example.com\",\"password\":\"attempt${i}\"}"done
Remediation: use express-rate-limit to throttle attempts on login routes:
Copy
// server.js (or where you configure middlewares)const express = require('express');const rateLimit = require('express-rate-limit');const app = express();const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // limit to 5 attempts per windowMs message: { error: 'Too many login attempts, please try again later.' }, standardHeaders: true, legacyHeaders: false,});app.use('/api/auth/login', loginLimiter);
Observation: Parameterized queries are used in many places, reducing SQL injection risk.
Remediation: Ensure all DB access uses parameterized statements or safe driver APIs. For MongoDB, validate query parameters and avoid allowing clients to inject operators like $where, $gt, or other expressions.
Observation: Some responses include user-supplied data without consistent HTML encoding.
Remediation: Apply context-aware output encoding (HTML, JavaScript, URL). Use templating engines with auto-escaping or sanitize HTML with libraries like DOMPurify.
Observation: express-validator is present but inconsistently applied.
Remediation: Define strict validation schemas for each endpoint (required fields, types, min/max lengths, allowed enumerations). Consider using a JSON schema validator like Ajv for consistent server-wide checks.
Implement rate limiting on auth endpoints (Immediate)
Add request body size limits (Immediate)
Replace weak JWT secret with secure env secret and rotate (High)
Ensure DB queries use parameterized methods (High)
Harden file endpoints against path traversal (High)
Apply consistent input validation and output encoding (Medium)
Add security headers (Helmet) and CSP as appropriate (Medium)
Copy
<Callout icon="warning" color="#FF6B6B">Never run exploit or brute-force scripts against systems you do not own or have explicit permission to test. Use these techniques only in controlled environments.</Callout>## Quick defensive patterns and examplesBelow are concise, actionable patterns to harden input handling in Node/Express apps.- Parameterized SQL queries: always use your driver’s parameterization features (e.g., node-postgres) rather than string concatenation.- Centralized input validation: use express-validator or Ajv to enforce schemas consistently across all endpoints.- Rate limiting and body-size limits: throttling plus reasonable payload size caps mitigate credential stuffing and DoS risks.- Output encoding and sanitization: escape or sanitize output according to the consumption context (HTML, JS, URL).- Security headers: use Helmet to add common headers and reduce client-side attack surface.Example: express-validator usage:```javascript// Example using express-validatorconst { body, validationResult } = require('express-validator');app.post('/api/auth/register', [ body('email').isEmail().normalizeEmail(), body('password').isLength({ min: 8 }),], (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() }); // proceed with validated input});```textUse Helmet for security headers:```javascriptconst helmet = require('helmet');app.use(helmet());
Input validation overlaps heavily with database security — validating and sanitizing data before it reaches the DB prevents many injection and corruption scenarios. Next, consider hardening queries, migration tooling, and connection handling.Additional remediation templates and resources are available in the course repository:
https://github.com/JeremyMorgan/Claude-Code-Reviewing-Prompts