Path

When a fetch sink fixes the host and lets the attacker influence only the path, two avenues open: traversal that escapes a constrained base path to reach other endpoints on the same internal host, and parser differentials where characters in the path position change which authority the request actually targets.

Escaping a fixed base path#

A sink that builds http://internal-api/v1/users/<input> constrains the attacker to a subtree, but ../ climbs out of it to any endpoint on the same host:

code
../../admin/config
..%2f..%2fadmin%2fconfig        # encoded, to pass a literal ../ filter
..%252f..%252fadmin             # double-encoded, where one decode happens before the check

This does not change the host, so it is useful when the internal host is already the target and the goal is reaching a sensitive path (an admin route, an actuator or debug endpoint, an unauthenticated internal API) that the intended base path hid.

Prefix allowlist bypass#

A common control checks that the assembled URL starts with an allowed prefix, for example https://storage.example.com/. Traversal and normalization defeat a naive prefix match when the client normalizes the path after the check:

code
https://storage.example.com/../../internal/secret
https://storage.example.com/..%2f..%2finternal%2fsecret

The string passes startsWith, and the client collapses the ../ segments to reach a different path than the prefix implied.

Authority and path parser differentials#

URL parsers disagree on where the authority ends and the path begins, and that disagreement lets a value that one component reads as a path redirect the host another component connects to. The characters that drive this are @, #, ?, and backslash:

code
http://allowed.example@127.0.0.1/          # userinfo trick: host is 127.0.0.1, not allowed.example
http://127.0.0.1#@allowed.example/         # fragment: real host is 127.0.0.1 before the #
http://127.0.0.1\@allowed.example/         # backslash: some parsers treat \ as /
http://allowed.example\@127.0.0.1/         # the reverse, depending on which parser validates

The attack is a differential: the validator parses the URL one way (seeing allowed.example as the host) while the HTTP client parses it another (connecting to 127.0.0.1). WHATWG-style parsers treat backslash as a path separator and resolve userinfo differently from older RFC 3986 parsers, so a sink that validates with one library and fetches with another is the vulnerable combination. Which payload works depends on the exact pair, so cycle through the @, #, and \ forms and watch which host the request reaches.

References#

Cookie Consent

We use cookies to enhance your experience. Learn more