Browser security notes: why URL parsing quirks matter
This note points at a narrow but persistent corner of browser security: the fact that no two pieces of software, a browser, a proxy, a web server, a backend framework, necessarily agree on how to parse the same URL string. Each was written against its own reading of the relevant specification, with its own history of edge cases patched in as they were discovered, and the result is a set of components that usually agree but occasionally do not.
Why disagreement is dangerous
A security check is only as good as the string it is checking. If a validation layer decides a URL or a path is safe based on its own parsing, but the component that actually acts on the URL, rendering a link, following a redirect, resolving a path, parses the same string differently, the two disagree about what the URL actually means. That gap is where a surprising number of browser-adjacent bugs live: open redirects that survive a same-origin check because the checker and the browser disagree about what counts as the origin, path traversal that survives a prefix check because the checker and the filesystem disagree about what a sequence of dots and slashes resolves to, and request-smuggling-style issues where a proxy and the backend disagree about where one request ends and the next begins.
Fuzzing is the practical way this class of bug gets found: feeding deliberately malformed or boundary-case URLs through a pipeline and watching where two components stop agreeing, rather than trying to reason out every edge case by hand. Each small variation, an extra slash, a different case, an unusual encoding, a stray backslash, is a chance to find a point where the specification was ambiguous and two implementations each picked a different interpretation.
What this means for defenders
Security decisions, such as origin checks, redirect allow-lists, and path containment checks, should be made by, or validated against, the same component that will actually act on the URL, not a second implementation that merely approximates it. Where that is not possible, normalising a URL to one canonical form before any decision is made closes off most of the disagreement. Treating a URL as a single unambiguous string, rather than remembering that every parser reading it has its own opinion, is the quiet assumption that this class of bug exploits.
Key takeaways
- Browsers, proxies, servers and frameworks don't always parse the same URL identically
- Security checks that trust their own parsing can disagree with whatever component actually acts on the URL
- This mismatch underlies open redirects, path traversal, and request-smuggling-style bugs
- Fuzzing malformed and boundary-case URLs is how these disagreements are usually found
- Normalise a URL to one canonical form before making a security decision on it
This note has been rewritten and checked for this edition; it is not a copy of the original post.