DOM XSS - HackTricks

# DOM XSS

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

## DOM Vulnerabilities

DOM vulnerabilities occur when data from attacker-controlled sources (like `location.search`, `document.referrer`, or `document.cookie`) is unsafely transferred to sinks. Sinks are functions or objects (e.g., `eval()`, `document.body.innerHTML`) that can execute or render harmful content if given malicious data.

- Sources are inputs that can be manipulated by attackers, including URLs, cookies, and web messages.
- Sinks are potentially dangerous endpoints where malicious data can lead to adverse effects, such as script execution.

The risk arises when data flows from a source to a sink without proper validation or sanitation, enabling attacks like XSS.

> [!NOTE] You can find a more updated list of sources and sinks in https://github.com/wisec/domxsswiki/wiki

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 | Javascript Injection | 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 | `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 | `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 | `someDOMElement.innerHTML` | `jQuery.parseHTML()`
`jQuery.globalEval()` | `someDOMElement.href` | `someDOMElement.outerHTML` | `$.parseHTML()`
`$.globalEval()` | `someDOMElement.src` | `someDOMElement.insertAdjacentHTML` | Client-side JSON injection
`` HTML5-storage manipulation | `someDOMElement.action` | `someDOMElement.onevent` | `JSON.parse()`
`sessionStorage.setItem()` | XPath injection | `document.write()` | `jQuery.parseJSON()`
`localStorage.setItem()` | `document.evaluate()` | `document.writeln()` | `$.parseJSON()`
`**[**`Denial of Service`**](dom-xss.md#denial-of-service)**` | `someDOMElement.evaluate()` | `document.title` | `` Cookie manipulation
`requestFileSystem()` | `` Document-domain manipulation | `document.implementation.createHTMLDocument()` | `document.cookie`
`RegExp()` | `document.domain` | `history.pushState()` | WebSocket-URL poisoning
Client-Side SQl injection | 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.

## Tools to find them

- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Browser extension to check every data taht reaches a potential sink: https://github.com/kevin-mizu/domloggerpp

## Examples

### Open Redirect

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

Open redirect vulnerabilities in the DOM occur when a script writes data, which an attacker can control, into a sink capable of initiating navigation across domains.

It's crucial to understand that executing arbitrary code, such as `javascript:alert(1)`, is possible if you have control over the start of the URL where the redirection occurs.

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

DOM-based cookie-manipulation vulnerabilities occur when a script incorporates data, which can be controlled by an attacker, into the value of a cookie. This vulnerability can lead to unexpected behavior of the webpage if the cookie is utilized within the site. Additionally, it can be exploited to carry out a session fixation attack if the cookie is involved in tracking user sessions. The primary sink associated with this vulnerability is:

Sinks:

    document.cookie

### JavaScript Injection

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

DOM-based JavaScript injection vulnerabilities are created when a script runs data, which can be controlled by an attacker, as JavaScript code.

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

Document-domain manipulation vulnerabilities occur when a script sets the `document.domain` property using data that an attacker can control.

The `document.domain` property plays a key role in the enforcement of the same-origin policy by browsers. When two pages from different origins set their `document.domain` to the same value, they can interact without restrictions. Although browsers impose certain limits on the values assignable to `document.domain`, preventing the assignment of completely unrelated values to the actual page origin, exceptions exist. Typically, browsers permit the use of child or parent domains.

Sinks:

    document.domain

### WebSocket-URL poisoning

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

WebSocket-URL poisoning occurs when a script utilizes controllable data as the target URL for 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

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

Ajax request manipulation vulnerabilities arise when a script writes attacker-controllable data into 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

Local file-path manipulation vulnerabilities arise when a script passes attacker-controllable data to a file-handling API as the `filename` parameter. This vulnerability can be exploited by an attacker to construct a URL that, if visited by another user, could lead to the user's browser opening or writing 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

Client-side SQL-injection vulnerabilities occur 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

HTML5-storage manipulation vulnerabilities arise when a script stores attacker-controllable data in the web browser's HTML5 storage (`localStorage` or `sessionStorage`). While this action is not inherently a security vulnerability, it becomes problematic if the application subsequently reads the stored data and processes it unsafely. This could allow an attacker to leverage the storage mechanism to conduct 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

DOM-based XPath-injection vulnerabilities occur 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

DOM-based JSON-injection vulnerabilities occur 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

Web-message vulnerabilities arise when a script sends attacker-controllable data as a web message to another document within the browser. An example of vulnerable Web-message manipulation can be found at PortSwigger's Web Security Academy.

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

DOM-data manipulation vulnerabilities arise when a script writes attacker-controllable data to a field within the DOM that is utilized within the visible UI or client-side logic. This vulnerability can be exploited by an attacker to construct a URL that, if visited by another user, can alter 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

DOM-based denial-of-service vulnerabilities occur when a script passes attacker-controllable data unsafely to a problematic platform API. This includes APIs that, when invoked, can lead the user's computer to consume excessive amounts of CPU or disk space. Such vulnerabilities can have significant side effects, such as the browser restricting the website's functionality by rejecting attempts to store data in `localStorage` or terminating busy scripts.

Sinks:

    requestFileSystem()
    RegExp()

## Dom Clobbering

Dom Clobbering

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.