Input Validation and Injection Defense
Ensure untrusted input is validated and never interpreted as code. Prevent injection across SQL, LDAP, OS commands, templating, and JavaScript runtime object graphs.
Core Strategy
- Validate early at trust boundaries with positive (allow-list) validation and canonicalization.
- Treat all untrusted input as data, never as code. Use safe APIs that separate code from data.
- Parameterize queries/commands; escape only as last resort and context-specific.
Validation Playbook
- Syntactic validation: enforce format, type, ranges, and lengths for each field.
- Semantic validation: enforce business rules (e.g., start <= end date, enum allow-lists).
- Normalization: canonicalize encodings before validation; validate complete strings (regex anchors
^$); beware ReDoS.
- Free-form text: define character class allow-lists; normalize Unicode; set length bounds.
- Files: validate by content type (magic), size caps, and safe extensions; server-generate filenames; scan; store outside web root.
SQL Injection Prevention
- Use prepared statements and parameterized queries for 100% of data access.
- Use bind variables for any dynamic SQL within stored procedures -- never concatenate user input into SQL.
- Prefer least-privilege DB users and views; never grant admin to app accounts.
- Escaping is fragile and discouraged; parameterization is the primary defense.
Example (Java PreparedStatement):
String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery();
LDAP Injection Prevention
- Always apply context-appropriate escaping:
- DN escaping for
\ # + < > , ; " = and leading/trailing spaces
- Filter escaping for
* ( ) \ NUL
- Validate inputs with allow-lists before constructing queries; use libraries that provide DN/filter encoders.
- Use least-privilege LDAP connections with bind authentication; avoid anonymous binds for application queries.
OS Command Injection Defense
- Prefer built-in APIs instead of shelling out (e.g., library calls over
exec).
- If unavoidable, use structured execution that separates command and arguments (e.g., ProcessBuilder). Do not invoke shells.
- Strictly allow-list commands and validate arguments with allow-list regex; exclude metacharacters (
& | ; $ > < \ ! ' " ( ) and whitespace as needed).
- Use
-- to delimit arguments where supported to prevent option injection.
Example (Java ProcessBuilder):
ProcessBuilder pb = new ProcessBuilder("TrustedCmd", "Arg1", "Arg2");
Map<String,String> env = pb.environment();
pb.directory(new File("TrustedDir"));
Process p = pb.start();
Query Parameterization Guidance
- Use the platform's parameterization features (JDBC PreparedStatement, .NET SqlCommand, Ruby ActiveRecord bind params, PHP PDO, SQLx bind, etc.).
- For stored procedures, ensure parameters are bound; never build dynamic SQL via string concatenation inside procedures.
Prototype Pollution (JavaScript)
- Use
new Set() or new Map() instead of object literals.
- When objects are required, create with
Object.create(null) or { __proto__: null } to avoid inherited prototypes.
- Freeze or seal objects that should be immutable; consider Node
--disable-proto=delete as defense-in-depth.
- Avoid unsafe deep merge utilities; validate keys against allow-lists and block
__proto__, constructor, prototype.
Caching and Transport
- Apply
Cache-Control: no-store on responses containing sensitive data; enforce HTTPS across data flows.
Implementation Checklist
Test Plan
- Static checks for string concatenation in queries/commands and dangerous DOM/merge sinks.
- Fuzzing for SQL/LDAP/OS injection vectors; unit tests for validator edge cases.
- Negative tests exercising blocked prototype keys and deep merge behavior.
1---2name: input-validation-injection3description: Apply when reviewing or writing code that processes untrusted input, constructs queries or commands, or handles user-supplied data. Covers SQL, LDAP, OS command injection, prototype pollution, and general validation strategy.4---56# Input Validation and Injection Defense78Ensure untrusted input is validated and never interpreted as code. Prevent injection across SQL, LDAP, OS commands, templating, and JavaScript runtime object graphs.910## Core Strategy1112- Validate early at trust boundaries with positive (allow-list) validation and canonicalization.13- Treat all untrusted input as data, never as code. Use safe APIs that separate code from data.14- Parameterize queries/commands; escape only as last resort and context-specific.1516## Validation Playbook1718- **Syntactic validation**: enforce format, type, ranges, and lengths for each field.19- **Semantic validation**: enforce business rules (e.g., start <= end date, enum allow-lists).20- **Normalization**: canonicalize encodings before validation; validate complete strings (regex anchors `^$`); beware ReDoS.21- **Free-form text**: define character class allow-lists; normalize Unicode; set length bounds.22- **Files**: validate by content type (magic), size caps, and safe extensions; server-generate filenames; scan; store outside web root.2324## SQL Injection Prevention2526- Use prepared statements and parameterized queries for 100% of data access.27- Use bind variables for any dynamic SQL within stored procedures -- never concatenate user input into SQL.28- Prefer least-privilege DB users and views; never grant admin to app accounts.29- Escaping is fragile and discouraged; parameterization is the primary defense.3031Example (Java PreparedStatement):3233```java34String custname = request.getParameter("customerName");35String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";36PreparedStatement pstmt = connection.prepareStatement(query);37pstmt.setString(1, custname);38ResultSet results = pstmt.executeQuery();39```4041## LDAP Injection Prevention4243- Always apply context-appropriate escaping:44 - DN escaping for `\ # + < > , ; " =` and leading/trailing spaces45 - Filter escaping for `* ( ) \ NUL`46- Validate inputs with allow-lists before constructing queries; use libraries that provide DN/filter encoders.47- Use least-privilege LDAP connections with bind authentication; avoid anonymous binds for application queries.4849## OS Command Injection Defense5051- Prefer built-in APIs instead of shelling out (e.g., library calls over `exec`).52- If unavoidable, use structured execution that separates command and arguments (e.g., ProcessBuilder). Do not invoke shells.53- Strictly allow-list commands and validate arguments with allow-list regex; exclude metacharacters (`& | ; $ > < \ ! ' " ( )` and whitespace as needed).54- Use `--` to delimit arguments where supported to prevent option injection.5556Example (Java ProcessBuilder):5758```java59ProcessBuilder pb = new ProcessBuilder("TrustedCmd", "Arg1", "Arg2");60Map<String,String> env = pb.environment();61pb.directory(new File("TrustedDir"));62Process p = pb.start();63```6465## Query Parameterization Guidance6667- Use the platform's parameterization features (JDBC PreparedStatement, .NET SqlCommand, Ruby ActiveRecord bind params, PHP PDO, SQLx bind, etc.).68- For stored procedures, ensure parameters are bound; never build dynamic SQL via string concatenation inside procedures.6970## Prototype Pollution (JavaScript)7172- Use `new Set()` or `new Map()` instead of object literals.73- When objects are required, create with `Object.create(null)` or `{ __proto__: null }` to avoid inherited prototypes.74- Freeze or seal objects that should be immutable; consider Node `--disable-proto=delete` as defense-in-depth.75- Avoid unsafe deep merge utilities; validate keys against allow-lists and block `__proto__`, `constructor`, `prototype`.7677## Caching and Transport7879- Apply `Cache-Control: no-store` on responses containing sensitive data; enforce HTTPS across data flows.8081## Implementation Checklist8283- [ ] Central validators: types, ranges, lengths, enums; canonicalization before checks84- [ ] 100% parameterization coverage for SQL; dynamic identifiers via allow-lists only85- [ ] LDAP DN/filter escaping in use; inputs validated prior to query86- [ ] No shell invocation for untrusted input; if unavoidable, structured exec + allow-list + regex validation87- [ ] JS object graph hardened: safe constructors, blocked prototype paths, safe merge utilities88- [ ] File uploads validated by content, size, and extension; stored outside web root and scanned8990## Test Plan9192- Static checks for string concatenation in queries/commands and dangerous DOM/merge sinks.93- Fuzzing for SQL/LDAP/OS injection vectors; unit tests for validator edge cases.94- Negative tests exercising blocked prototype keys and deep merge behavior.