The URL with the exercise is: https://portswigger.net/web-security/ssrf/lab-ssrf-with-whitelist-filter

The solution is:

A little simplified (no port specified):

We can concentrate simply on:

Why is the credential component (everything before the @) processed as if everything after the @ is part of a URL fragment? Before double encoding the # character, the URL looks like this:

Why is the @ even necessary, even after we double encode the #? Why does http://localhost%2523stock.weliketoshop.net (not no '@') not work? Does the url fragment statement take priority over the credential statement? Why is the @ ignored in favor of the #?

  • 1
    I'm not sure this is a security question. This looks like a basic URL standards question.
    – schroeder
    Mar 3 '20 at 8:24

As per the RFC 3986:-

The userinfo subcomponent may consist of a user name and, optionally, scheme-specific information about how to gain authorization to access the resource. The user information, if present, is followed by a commercial at-sign ("@") that delimits it from the host.

RFC3986 section-3.2.1


I played with this recently. The SSRF filter is checking to see if the parameter value is an actual URL with a stock.weliketoshop.net hostname. It's not a simple string check. That's why if we use http://localhost%2523stock.weliketoshop.net it sees it as http://localhost#... and not working.

If you add '@' then the filter sees http://username@stock.weliketoshop.net which is the accepted hostname. Now if we use http://localhost%2523@stock.weliketoshop.net that passes the filter and the web server directs it to http://localhost#...

The mysterious part is why http://localhost%2523@stock.weliketoshop.net/admin works. It looks like there's another filter that strips everything from %25 until it sees / and concatenates, which leads tohttp://localhost/admin. The normal web server should ignore /admin at the end as it's after the # segment.

I enumerated all the characters and discovered that %252f and $253f also work which are / and ? respectively. I tried http://localhost%252fadmin%2523@stock.weliketoshop.net which still passes the filter and makes more sense but again the result was that everything after %25 was stripped so it goes to http://localhost only.

My conclusion is that Portswigger created a custom filter for the sake of the tutorial which doesn't exactly resemble a real-world SSRF filter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.