Validation bugs come in three flavors. The check is too narrow: a regex matches "looks like an email" but accepts ";--. The check is on the wrong layer: client-side JS rejects bad input but the API doesn't repeat the check. The check is bypassed by encoding: the input is decoded after validation, turning a benign string into a malicious one.
A common modern shape: a schema validator (Zod, Pydantic, Joi) is configured with passthrough or extra=allow, so unrecognized fields slip through to the database. Another: number fields with no range check, accepting Infinity or -1 where a positive integer was expected.
Defense in depth helps. Validate at the boundary, again before any sensitive operation, and again at the database with constraints. The boundary check is the only one a thoughtful attacker doesn't get to skip.
Review heuristic
Read every schema definition asking: what's the smallest set of values this field actually means? If the schema admits more than that — wrong types, out-of-range numbers, extra unknown fields — the validation is leaky.
External reference
CWE-20: Improper Input Validation — the canonical industry classification for this bug class. Useful when filing tickets, writing security policies, or arguing with a static analyzer.