Input Validation: Enforcing Expectations at Trusted Boundaries
📑 On this page
- A concrete example: item quantity
- What counts as input?
- Syntactic validation
- Semantic validation
- Allow lists
- Type and coercion
- Length and size limits
- Numeric ranges
- Dates and time
- Identifiers
- File uploads
- Path handling
- Canonicalization
- Validation versus sanitization
- Output encoding
- Database queries
- Error messages
- Validation location
- Schema validation
- Testing validation
- Knowledge check
- The one idea to remember
Every interface receives data from somewhere else.
Browsers, mobile apps, files, APIs, queues, and databases can send malformed, stale, hostile, or simply unexpected values.
Validate external input at the boundary where the system exercises authority.
Client-side checks improve usability, but an attacker can bypass the client and call the server directly.
A concrete example: item quantity
The website prevents a shopper from entering a negative quantity.
An attacker sends an API request manually:
quantity: -100The server validates the business rule and rejects it. Without server enforcement, the client interface would be mistaken for a security boundary.
What counts as input?
Input includes:
- URL and query parameters,
- headers,
- cookies,
- JSON and form bodies,
- uploaded files,
- database records,
- queue messages,
- environment variables,
- command-line arguments,
- and third-party API responses.
Trust depends on the boundary and authority, not whether the source is "internal."
Syntactic validation
Syntactic validation checks representation:
- type,
- format,
- length,
- encoding,
- required fields,
- and structure.
Examples:
- integer,
- valid date format,
- UUID shape,
- maximum 200 characters,
- known JSON schema.
Semantic validation
Semantic validation checks meaning:
- quantity must be positive,
- end date follows start date,
- account is active,
- currency matches merchant,
- requested transition is allowed.
A value can be syntactically valid and still violate business rules.
Allow lists
When accepted values are known, use an allow list:
status in {draft, submitted, approved}Trying to list every dangerous string is brittle because attackers can encode or combine values in unexpected ways.
Allow the supported domain rather than guessing all invalid possibilities.
Type and coercion
Automatic conversion can create ambiguity:
- empty string becomes zero,
"false"becomes true in some contexts,- large number loses precision,
- date changes time zone.
Parse explicitly and reject ambiguous values. Use domain types for money, identifiers, and dates.
Length and size limits
Set limits before expensive processing:
- body size,
- file size,
- string length,
- array length,
- nesting depth,
- decompressed size,
- and number of fields.
A tiny compressed input can expand enormously, creating a decompression bomb.
Numeric ranges
Check:
- minimum,
- maximum,
- precision,
- sign,
- and overflow.
Financial values should use decimal or integer minor units according to the domain, not unsafe floating-point assumptions.
Dates and time
Validate:
- format,
- time zone,
- impossible dates,
- allowed range,
- and business meaning.
"2026-02-30" is structured like a date but does not exist. A birth date in the future is a semantic error.
Identifiers
A valid identifier format does not prove access.
After parsing an order ID, the server must still verify:
- resource exists,
- caller owns or may access it,
- and requested action is allowed.
Validation and authorization solve different problems.
File uploads
Validate:
- total size,
- actual content type,
- extension where relevant,
- parser behavior,
- dimensions,
- archive contents,
- filename,
- and storage location.
Do not trust the browser-provided MIME type or original filename alone.
Path handling
User-controlled paths can escape intended directories through values such as ../.
Use safe storage APIs, generated filenames, resolved-path checks, and explicit roots. Do not build filesystem paths through raw string concatenation.
Object identifiers are often safer than exposing server paths.
Canonicalization
The same logical value can have several representations through Unicode, URL encoding, case, path separators, or repeated decoding.
Normalize once using a defined standard before applying comparisons and allow lists, then preserve the original only when the product needs it. Validation before one layer decodes the value again can allow a forbidden representation to reappear.
Validation versus sanitization
Validation decides whether input is acceptable.
Sanitization transforms input into a permitted form, such as normalizing a phone number. Silent transformation can change meaning, so use it only with clear rules.
Do not "sanitize" SQL or HTML with homemade character removal.
Output encoding
Input validation does not replace context-aware output encoding.
A person's name may legitimately contain punctuation that becomes dangerous only when inserted into HTML, JavaScript, SQL, or a shell incorrectly.
Keep data separate from executable syntax using safe APIs and encode for the destination context.
Database queries
Use parameterized queries.
Even a validated value should not be concatenated into SQL. Validation can change later, and one missed field reintroduces injection.
Parameterized structure is the primary control; validation enforces domain rules.
Error messages
Return useful but safe errors:
- field,
- expected rule,
- retry guidance.
Avoid exposing stack traces, SQL, secret values, or internal paths.
Collect detailed context securely for operators.
Validation location
Validate at each trust boundary:
- edge for size and syntax,
- application for domain rules,
- database for constraints,
- consumer for message contract.
Layers have different authority. Do not rely on one distant upstream check forever.
Schema validation
Schemas can enforce:
- required fields,
- types,
- allowed values,
- nesting,
- and version.
Generated validators improve consistency, but custom business logic remains necessary.
Reject or deliberately ignore unknown fields according to compatibility and security needs.
Testing validation
Test:
- boundaries,
- missing versus null,
- wrong type,
- extra fields,
- Unicode,
- huge input,
- malformed encoding,
- duplicate fields,
- and business-rule conflicts.
Property-based testing and fuzzing can discover unexpected parser behavior.
Knowledge check
- Why is client-side validation not a security boundary?
- How do syntactic and semantic validation differ?
- Why are allow lists usually stronger than block lists?
- Why does a valid resource ID not prove authorization?
- How does validation differ from output encoding?
The one idea to remember
Validate every external value for structure, type, size, range, and business meaning at the trusted server boundary. Keep validation separate from authorization and context-aware encoding, and use safe structured APIs instead of trying to remove dangerous characters.