# 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
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921769892/d16ea087-68a4-4bd5-b145-d1fb87396c3a.png align="center")
    
* 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
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921784615/8e18bf3f-a74f-425e-baef-16e37b658571.png align="center")
    
* After that, go back to the blog to view the newly added comment
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921798885/8ab5b833-c45d-458a-a109-87c395d86b8a.png align="center")
    
* 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
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921809008/3082e718-fa44-4597-9288-30890d541e5f.png align="center")
    
* 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:
        
        * They follow the structure `scheme://authority/path?query#fragment`
            
        * Example: [`https://example.com/path/to/page`](https://example.com/path/to/page)
            
    * 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:
        
        ```jsx
        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
    
    ```jsx
    javascript:alert(1);
    ```
    
* Lets add this payload inside the Website link form parameter by creating a new comment. Click on the Post Comment button
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921826832/ea2f7d9a-fecb-4ced-ad7a-e6021c11db38.png align="center")
    
* As soon as we submit the comment, we can see a notification that we have successfully solved the lab
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921843784/52334560-1d26-47ae-bf43-5c96831bbeba.png align="center")
    
* 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
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921854679/1c3a3268-8fc3-4b43-bee0-ca5ea73b8d4c.png align="center")
    
* 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`
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1763921864860/ffd7d13a-d534-459f-b079-f0fd809bb481.png align="center")
    
* 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:

| Type | Example | Hierarchical? | Explanation |
| --- | --- | --- | --- |
| **Hierarchical** | [`https://example.com/path/to/page`](https://example.com/path/to/page) | ✅ Yes | They follow the structure `scheme://authority/path?query#fragment`. |
| **Non-hierarchical** | `mailto:logan@example.com` | ❌ No | No `//authority` part - structure depends entirely on the scheme definition. |

### Structure of a hierarchical URL

Hierarchical URLs have this **general pattern**:

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

Example:

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

Here:

* `scheme` = `https`
    
* `authority` = [`example.com`](http://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`](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:

| Scheme | Example | What it means |
| --- | --- | --- |
| `mailto:` | `mailto:logan@example.com` | Open default email client to send mail to that address |
| `tel:` | `tel:+919999999999` | Open 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:

```javascript
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`](mailto:rehan@example.com)

* Scheme: `mailto`
    
* Remainder: [`logan@example.com`](mailto:rehan@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`.
