document.baseURI to build a part of the page without sanitization.
This type of attack is explained in detail in the following article: DOM XSS: An Explanation of DOM-based Cross-site Scripting. For more information on other types of XSS attacks: reflected XSS and stored XSS, see the following article: Types of XSS: Stored XSS, Reflected XSS, and DOM-based XSS.
An Example of DOM XSS
One of our Vulnweb test sites features a DOM-based XSS vulnerability that can be exploited using the following payload:
The result can be seen in the following image. It is an informational message with a simple alert. Note how the payload is stored in the
GET request, making it suitable for social engineering attacks.
The payload can be manipulated to deface the target application using a prompt that states: Your session has expired. Please insert your password to refresh your session. It is a simple yet effective way to harvest passwords using only the victim’s browser.
<script> var redirUrl = decodeURIComponent(window.location.hash.slice(window.location.hash.indexOf("?url=")+5)); if (redirUrl) window.location = redirUrl; </script>
Essentially, the exploit uses the
window.location.hash source, which is evaluated in an HTML element sink. For information on sources and sinks, read the following article: Finding the Source of a DOM-based XSS Vulnerability with Acunetix.
How To Prevent DOM XSS
The primary rule that you must follow to prevent DOM XSS is: sanitize all untrusted data, even if it is only used in client-side scripts. If you have to use user input on your page, always use it in the text context, never as HTML tags or any other potential code.
Avoid methods such as
document.innerHTML and instead use safer functions, for example,
document.textContent. If you can, entirely avoid using user input, especially if it affects DOM elements such as the
document.location, or the
Also, keep in mind that DOM XSS and other types of XSS are not mutually exclusive. Your application can be vulnerable to both reflected/stored XSS and DOM XSS. The good news is that if user input is handled properly at the foundation level (e.g. your framework), you should be able to mitigate all XSS vulnerabilities.
How To Detect DOM XSS
It is almost impossible to detect DOM XSS only from the server-side (using HTTP requests). Most DOM XSS payloads are never sent to the server because they are prepended by the
# symbol. This means, that no data will be available in server logs. This fact makes it more difficult to maintain web application security.
To detect the possibility of a DOM XSS, you must simulate the attack from the client-side in the user’s browser using a web application scanner like Acunetix (with DOM-based XSS scanner functionality). Acunetix uses its DeepScan technology to attempt DOM XSS against the client-side code and report vulnerabilities.
DOM-based XSS Cheat Sheet
For more details on how to prevent DOM-based XSS attacks, you can read the OWASP DOM-based XSS Prevention Cheat Sheet.
Frequently asked questions
DOM-based cross-site scripting (DOM XSS) is a web vulnerability, a subtype of cross-site scripting. An attacker can execute a DOM-based cross-site scripting attack if the web application writes user-supplied information directly to the Document Object Model (DOM) and there is no sanitization.
Based on our research summarized in the Acunetix Web Application Vulnerability Report, DOM-based cross-site scripting is not very common – such vulnerabilities exist only in approximately 1.2% of analyzed web applications. Despite being rare, they may cause serious problems and only a few scanners can detect them.
It is difficult to detect DOM-based cross-site scripting because very often it leaves no mark on the server at all (for example, in server logs) – the whole attack happens in the client. It is also impossible to protect against such client-side attacks using WAFs. Your best bet is to use a vulnerability scanner with a DOM-based cross-site scripting detection module. For example, Acunetix.
To prevent DOM-based cross-site scripting, sanitize all untrusted data, even if it is only used in client-side scripts. If you have to use user input on your page, always use it in the text context, never as HTML tags or any other potential code. Use only safe functions like document.innerText and document.textContent.
Get the latest content on web security
in your inbox each week.