Skip to main content

Command Palette

Search for a command to run...

PortSwigger XSS Lab: Stored XSS

Stored XSS into anchor href attribute with double quotes HTML-encoded

Updated
5 min read
PortSwigger XSS Lab: Stored XSS

Description

This lab contains a stored cross-site scripting vulnerability in the comment functionality.

Task

To solve this lab, submit a comment that calls the alert function when the comment author name is clicked.

Methodology

  • Add the Target URL in Burpsuite Scope

  • This is our target website

  • As per the description, the XSS vulnerability is present in the comment section

  • Click on any post. Scroll down to the comment section. Open the dev console.

  • Lets add a new comment in the comment section of the blog as shown in the below image

  • After that, go back to the blog to view the newly added comment

  • Lets check the comment author name where the XSS vulnerability might be present

  • Analyze the comment author name and view its code in the inspector tab

  • As seen in the above image, the href attribute stores the Website form parameter. It stores them as a hyperlink (which is clear from the <a> tag)

  • If we click on the comment author name, we would be redirected to the hyperlink inside the href attribute

  • So, if we want to trigger XSS, we have to store the payload inside the href attribute

  • Here, we can use the concept of Hierarchical and Non-Hierarchical URLs

    • Hierarchical URL:

    • Non-Hierarchical URL:

      • No //authority part — structure depends entirely on the scheme definition.

      • Example: javascript://

Note: A short summary will be given for the concept of Hierarchical and Non-Hierarchical URLs above. For further explanation, kindly visit the bottom of the current page

  • We can use the javascript:// - non-hierarchical URL to run inline JavaScript code. It’s used to execute JavaScript directly when a link or address bar is used.

    • Example:

        javascript:alert('Hello World');
      
    • When this URL is visited (for example, in a browser address bar or <a href>), the browser executes the JavaScript code instead of loading a page.

  • Using the above information, we will now create the below XSS payload

      javascript:alert(1);
    
  • Lets add this payload inside the Website link form parameter by creating a new comment. Click on the Post Comment button

  • As soon as we submit the comment, we can see a notification that we have successfully solved the lab

  • Lets try to invoke the XSS payload stored inside the href attribute of the comment author name inside the <a> tag

  • We will go back to the blog and analyze the author name hyperlink

  • As seen in the above image, the Stored XSS Payload has successfully saved inside the href attribute

  • To invoke the payload, click on the comment author name Wolf3

  • We have successfully triggered Stored XSS on the target website

  • Using the above payload, we have used the non-hierarchical URL javascript:// to run inline javascript code inside the href attribute of the <a> tag belonging to the comment author name. Thereby, executing a Stored XSS on the target website

Hierarchical v/s Non-Hierarchical URL

URL classification in RFC 3986

According to RFC 3986 (Uniform Resource Identifier: Generic Syntax),

URLs (URIs) can be broadly categorized as:

TypeExampleHierarchical?Explanation
Hierarchicalhttps://example.com/path/to/page✅ YesThey follow the structure scheme://authority/path?query#fragment.
Non-hierarchicalmailto:logan@example.com❌ NoNo //authority part - structure depends entirely on the scheme definition.

Structure of a hierarchical URL

Hierarchical URLs have this general pattern:

<scheme>://<authority><path>?<query>#<fragment>

Example:

<https://example.com/blog/article?id=10#comments>

Here:

  • scheme = https

  • authority = example.com

  • path = /blog/article

  • query = id=10

  • fragment = comments

Because of this structured layout, these URLs can be resolved relative to one another, e.g.,

/blog/article relative to https://example.com → hierarchical traversal is possible.

Structure of a non-hierarchical URL

Non-hierarchical URLs omit the authority and path entirely.

They don’t follow the // or / folder structure.

Instead, the content after the scheme is directly defined by that specific protocol’s syntax.

Examples:

SchemeExampleWhat it means
mailto:mailto:logan@example.comOpen default email client to send mail to that address
tel:tel:+919999999999Open phone dialer with number
data:data:text/plain;base64,SGVsbG8=Embed inline data (e.g., text, image)
javascript:javascript:alert('XSS')Execute inline JavaScript in browser context

All of these are defined independently of hierarchical syntax — they don’t have //authority or path.

How browsers parse non-hierarchical URLs

When a browser sees a URL:

scheme:something

it checks whether the scheme’s definition uses hierarchical syntax or non-hierarchical syntax.

If the scheme is non-hierarchical, the browser:

  1. Skips the authority and path parsing steps.

  2. Passes the rest of the text (after the colon) directly to that protocol’s handler.

  3. Executes the handler defined in the browser or OS.

Example breakdown

mailto:logan@example.com

  • Scheme: mailto

  • Remainder: logan@example.com

  • Browser action: Open mail client with “To” filled in.

javascript:alert(1)

  • Scheme: javascript

  • Remainder: alert(1)

  • Browser action: Execute code in page context.

Security considerations

Because non-hierarchical schemes bypass normal navigation and go straight to browser handlers:

  • javascript: can lead to XSS or bookmarklet abuse.

  • data: can embed inline malicious payloads.

  • mailto: and tel: can be used in phishing/social engineering.

Hence, modern browsers restrict them:

  • Many contexts block javascript: URLs (inside iframe, a href in sandboxed pages, etc.).

  • CSP (Content Security Policy) can disable javascript: entirely via script-src.

76 views