URL encoder/decoder · Guide

URL Encoding Abuse: Attack Attempts and How to Stop Them

URL encoding attacks exploit one thing: two components disagree about what a URL means. A filter reads the raw string, the application reads the decoded one, and anything they interpret differently is an opening.

Double encoding

A filter blocking ../ sees %252e%252e%252f and finds nothing suspicious. The web server decodes once to %2e%2e%2f, the application decodes again to ../, and the traversal succeeds.

The root cause is decoding more than once. Decode exactly once, at a single well-defined boundary, then validate. If a value still contains % escapes after decoding, that is a signal worth rejecting rather than helpfully decoding again.

Alternate representations

The same character has many encodings, and filters that match strings miss most of them:

Text
../          plain
%2e%2e%2f    percent-encoded
%252e%252e   double-encoded
..%c0%af     overlong UTF-8 (invalid, historically accepted)
..%5c        backslash, normalised to / by browsers

Overlong UTF-8 encodes an ASCII character in more bytes than needed. It is invalid by specification, and decoders that accept it anyway have caused real vulnerabilities — the IIS Unicode traversal being the classic case.

Where it bites in modern apps

Open redirects: a validator checking startsWith("/") accepts /%09/evil.com or /\evil.com, both of which browsers resolve off-site.

Path traversal in file-serving endpoints, SSRF filters that block localhost but not %6c%6fcalhost, and cache poisoning where a proxy and an origin normalise a URL differently.

Defending properly

Validate after decoding, never before, and decode exactly once. Compare against an allowlist of permitted values rather than a denylist of dangerous patterns — you cannot enumerate every encoding, but you can enumerate what is allowed.

For redirects and any URL you act on, parse rather than string-match:

JavaScript
const target = new URL(input, location.origin);
if (target.origin !== location.origin) reject();

For file paths, resolve to an absolute path and confirm it is still inside the intended directory. A WAF is a useful extra layer and never the primary control — its job is pattern matching, which is exactly what these attacks defeat.

Frequently asked questions

What is a double encoding attack?

Encoding a payload twice so a filter sees harmless text while a component that decodes again sees the real payload.

Should I decode input repeatedly until it stops changing?

No. That is the vulnerability. Decode once and reject values that still contain escapes.

Is a WAF enough protection?

No. WAFs match patterns and encoding attacks exist to defeat pattern matching. Validate in the application after decoding.

Ready to try it?

Open the free browser-based URL encoder/decoder and apply what you just read — no sign-up, runs locally.

Open the URL encoder/decoder tool