Security

Decode, then validate.

A surprising number of input-validation bugs share one root cause: the check runs against encoded input, but the application acts on the decoded value. This guide explains why that ordering fails and how to harden your input handling — canonicalize first, validate with allowlists, and keep the two encodings straight. It’s about defending your own inputs, not attacking anyone’s.

The core mistake: validating before canonicalizing

Percent-encoding is reversible and has multiple equivalent forms. /, %2F, and %2f all mean the same character; a value can even be encoded more than once. A validator that inspects the raw request sees only the surface string. If it’s looking for a specific character or pattern and that character arrived encoded, the check passes — and then a later layer of the stack decodes the value into the very thing the filter was meant to stop.

The principle that fixes this comes straight from OWASP: reduce input to a single canonical form before you make any security decision about it. In practice, for URL input that means fully percent-decoding, then normalizing case and Unicode, and only then validating.

Why blocklists lose and allowlists win

The instinct to “block the dangerous characters” is the weaker half of the problem. Blocklists fail for two reasons:

An allowlist inverts the logic: define what is permitted — a character category (letters, digits), a length range, a format, or a fixed set of known-good values — and reject everything else. OWASP recommends allowlisting as the primary approach, with a blocklist used only as an extra layer to catch common patterns, never as the main line of defence.

Handling double-encoding safely

Double-encoding is the classic way a single-pass decoder gets fooled: %252F decodes once to the harmless-looking %2F, passes validation as text, then decodes again downstream to /. Two defensive habits close this:

OWASP’s ASVS puts it directly: decode into a canonical form once, only when encoded data in that form is expected, and do it before processing further — and store data decoded, not re-encoded, so you don’t reintroduce layers later.

A defensive checklist

Pulling it together, the order of operations for untrusted input that may be URL-encoded:

Notice this guide names no payloads and teaches no bypasses — the value is entirely in getting the ordering right. Most encoding-related input bugs disappear when “decode, then validate, then parameterize” is the fixed pipeline.

Sources & standards

Honest scope: this is a defensive input-handling guide focused on the encoding dimension. It is not a complete security program — consult the full OWASP cheat sheets and your framework’s security docs, and combine these practices with authentication, authorization, and monitoring.

Common questions

About input hardening.

Because they usually inspect the raw, still-encoded input. A filter looking for a literal dangerous substring won’t see it if the same characters arrive percent-encoded — the encoded form is a different string. The application decodes it later, after the check has passed. The fix is to decode to a canonical form first, then validate the decoded value.

Canonicalization means reducing input to one standard form before making any security decision about it. For URLs that means fully percent-decoding (and normalizing case and Unicode) so %2F and /, or %3a and %3A, become the same thing. OWASP’s guidance is to decode into a canonical form once, only when encoded data is expected, and to do it before processing the input further.

A validator that decodes input once and then checks it can be evaded by encoding twice: the first decode turns %252F into %2F, which passes the check as harmless text, and a later layer decodes it again into /. The defence is to decode fully to a stable canonical form — decode until the value stops changing — before validating, and to reject input that was encoded more times than expected.

An allowlist. Define exactly what is permitted — character categories, length, format, a set of known-good values — and reject everything else. Blocklists of “bad” characters or patterns are routinely bypassed with new encodings, Unicode variants, and casing tricks, and they also reject legitimate input (the classic example is a name like O’Brian being blocked for containing an apostrophe).

No — they solve different problems and work together. Input validation (after canonicalization) keeps malformed data out; context-aware output encoding ensures data is rendered safely when it leaves your app. OWASP is explicit that output encoding is the primary defence against injection in the output context, while input validation is defense-in-depth. Use both, plus parameterized queries for databases.

On a trusted system — the server — not solely in the browser. Client-side checks improve the user experience but can be skipped entirely by an attacker sending requests directly. Decode to canonical form and validate server-side, and store data in its original decoded state rather than re-encoded, to avoid double-encoding issues down the line.

Related

Keep reading.

About this page

Written and maintained by the urlencodedecode.com team. Every technical claim on this page is verified against primary sources — the RFCs (3986, 3629, 4648, 7578), the WHATWG URL Standard, and official vendor or language documentation — rather than second-hand summaries. When a source contradicts a common assumption, we follow the source and note the discrepancy. Corrections: contactus@urlencodedecode.com.