Two different defenses that people constantly mix up. One checks format. The other prevents injection.
| Input Validation | Output Encoding | |
|---|---|---|
| Purpose | Ensure data matches expected format | Make data safe for a specific output context |
| When it runs | On input — before processing | On output — before rendering |
| Example | Reject if email doesn't match pattern | Convert < to < before HTML |
| Prevents | Malformed data, some injection | XSS, injection in the output context |
| Context-aware? | No — validates against a generic rule | Yes — different encoding for HTML, JS, URL, CSS |
| Sufficient alone for XSS? | No | Yes (when applied correctly in every context) |
| Can be bypassed? | Often — via encoding tricks, edge cases | Rarely — if the right encoding is used |
Teams implement input validation (reject anything with <script>) and think they're protected against XSS. They're not. Input validation is a denylist approach — you're trying to predict every possible attack string. Attackers have infinite creativity and encoding tricks.
Output encoding is an allowlist approach — you're saying "in this HTML context, these characters have special meaning, so escape them." It doesn't matter what the attacker sends because the encoding neutralizes it at render time.
Input validation is still valuable — reject obviously malformed data early, enforce length limits, check types. It reduces your attack surface and catches accidental garbage. But it's defense in depth, not your primary XSS defense.
Output encoding is the actual fix. And it has to be context-aware: HTML entities for HTML body, JavaScript escaping for inline JS, URL encoding for URL parameters, CSS escaping for style contexts. Using HTML encoding inside a JavaScript string doesn't help.
Modern frameworks (React, Angular, Vue, Django templates, Rails ERB) auto-encode output by default. The danger is when you bypass it — React's dangerouslySetInnerHTML, Django's |safe filter, Rails' raw(). Every time you reach for one of those, you're opting out of your primary XSS defense.