← Safe Online
ASTERXOR / Safe Online

The same-looking link can contain different bytes

Percent encoding is a useful writing system for URLs, but reading and interpreting it are different operations.

Original explanatory illustration for The same-looking link can contain different bytes.
An original schematic using only fictional examples.
Safe OnlineASTERXOR / LEON LEUNG

When does a slash mean a separator, and when is it part of an encoded value?

A web address is structured text. Some characters have jobs as separators, while others belong to the values being carried. Percent encoding represents bytes using a percent sign and hexadecimal digits. It helps move data through that structure, but software must still decide which component it is interpreting and when decoding should happen. A readable version can hide those distinctions.

A clearer display is not a complete interpretation.
THE QUESTION

Encoding is not secrecy

The sequence %20 commonly represents a space byte in a URL component. Reading it does not require a key. Percent encoding is a representation technique, not encryption and not evidence that a destination is trustworthy. A long address full of escapes may be ordinary application data; an attractive short address may still lead to an unsuitable request.

The useful distinction is between the literal string, its parsed components and a decoded display of one component. Treating those stages as interchangeable can create surprises. A slash normally separates path segments, for example, while an encoded slash may be handled differently by different servers and routing layers. The meaning comes from the system processing it, not from appearance alone.

A SMALL MODEL

Two paths can look alike after one decoding pass

Our local fixtures include https://example.com/a%2Fb and https://example.com/a/b. Their raw paths differ. Applying one generic percent-decoding pass to the first yields /a/b, matching the second’s displayed path. Both literal URLs have hostname example.com. That is a result about string parsing and decoding, not evidence that a real server returns the same resource for both.

Another fixture contains an encoded example.org address inside the query of an example.com URL. The parsed outer hostname remains example.com. A nested address is data in that query until some application chooses what to do with it. It may be used for a later redirect, or for something else entirely. Our exercise never contacts either destination.

The first two raw paths converge after decoding; a double-encoded path changes again on a second pass.
FIG 01The first two raw paths converge after decoding; a double-encoded path changes again on a second pass.
READ THE RESULT

Decoding twice is a different operation

The path /%252F illustrates why stages matter. One decoding pass produces /%2F because %25 represents a percent sign. A second pass produces two slashes. The successive strings are different, even though a hurried reader might think of each as another way to write the same thing. Software that unexpectedly decodes twice can interpret data differently from software that decodes once.

We demonstrate this with an ordinary library function and fixed strings, not a working exploit. Real browsers, proxies, frameworks and servers have their own rules. A helper that prettifies a URL should not automatically become a security filter. Deciding which representations are equivalent requires the behavior of the actual system and a carefully defined policy.

THE BOUNDARY

For readers, a separate route is often easier

You do not need to manually decode a confusing address before deciding whether to enter a password. When a message claims that an account needs attention, open the usual app or saved bookmark and check there. A familiar hostname matters, but the requested action and how you arrived still deserve attention. HTTPS does not make every request appropriate.

If you do inspect an address, start with its actual scheme and hostname rather than searching the whole string for a recognizable word. Notice whether the apparent destination appears only inside a path or query. Shortened links and redirects add later steps that a literal reading cannot resolve. If the next action is consequential, uncertainty is a reasonable reason to pause.

Parse components before discussing their interpretation; then assess the proposed action separately.
FIG 02Parse components before discussing their interpretation; then assess the proposed action separately.
IN PRACTICE

For builders, preserve the context of each component

Developers should use established URL and framework APIs rather than a chain of ad hoc replacements. Validation and comparison must agree with the component that ultimately consumes the URL. A rule that checks one representation while another layer acts on a different one can create a gap. This article does not provide a deployable allowlist or normalization algorithm.

For everyone else, the lesson is smaller and more practical: some complexity belongs to the address format, but complexity should not pressure you into trusting an opaque request. Keep an independent route to important services. Reading a link well is helpful; knowing when not to resolve its ambiguity yourself is also a useful skill.

Further reading

RFC 3986: URI generic syntax ↗Python: URL parsing security ↗WHATWG: URL Standard ↗

Original documentation and useful background.

THE THOUGHT TO TAKE AWAY

The address has a grammar. Let that grammar slow the decision down when the display makes it look too easy.