DOM XSS: the basics

What is DOM XSS?

Document Object Model (DOM) cross-site scripting (XSS) is a web application vulnerability that allows attackers to manipulate the DOM environment in a user's browser by injecting malicious client-side code. In contrast to reflected or stored XSS, where the vulnerability is caused by server-side flaws and the payload is reflected in the response, DOM XSS is purely client-side.

DOM XSS vulnerabilities are mainly attributed to situations where user-controllable sources pass data to sinks, such as eval(), document.write, or innerHTML. These sinks allow for dynamic code execution.

Quick brief on the DOM

The DOM is an integral part of modern web applications, as it allows web applications to dynamically manipulate objects without making another trip back to the server. It works by representing data in nodes and objects for a web page in a hierarchical structure so that programming languages can interact with the page. The DOM's purpose is to allow web applications to modify their data by addressing each object on the page. Objects can be the actual content, styling or scripts, or data stored in a user’s browser that the website might need to access, such as cookies.

About this lesson

This lesson will build your fundamental knowledge about DOM XSS. We’ll walk through an example of exploiting DOM XSS vulnerabilities, we'll look at some vulnerable code, and how to fix the code to remove the vulnerability.

Fun Fact

Facebook's Bug Bounty

In 2020, a security researcher named Vinoth Kumar exploited the “Login with Facebook” button that allows third-party websites to authenticate users through Facebook. The vulnerability allowed attackers to take over Facebook accounts, earning Kumar a $20,000 Bug Bounty!

DOM XSS in action

Zane is a new developer at the software company Friendy.io, a social media site for trendy friends. He’s just implemented a personalized color feature for users' profiles, to ensure that they have complete creative control over their brand.

Our job is to perform security assurance work on Zane's new feature. Let’s start testing and see if the new feature is vulnerable to DOM XSS.

Testing for DOM XSS

  • STEP 1
  • STEP 2
  • STEP 3
  • STEP 4
  • STEP 5

Setting the stage

The first step is to perform some basic testing.

friendly.io start page

DOM XSS under the hood

In the previous example, we injected a malicious JavaScript code block into the website by escaping a query parameter. The function in the site that allowed this was modifying the DOM in an unsafe way; let’s explore what happened in more detail.

Most websites can receive dynamic data and update their content. When dangerous methods are used to achieve this, it can have unintended side effects that lead to security vulnerabilities. Sites also tend to store a plethora of information in the session, mainly in the form of cookies. These may include advertising IDs, user preferences, login credentials, email addresses, and more.

This code uses the document.write sink, which can create script elements. This is an executable path where untrusted user-supplied input can propagate from the URL query parameter to the DOM. Also, there is no validation or processing in place.

DOM XSS mitigation

The best way to mitigate this particular example is to remove the document.write method by assigning the color value directly to the document.body.style.color property. This eliminates the ability to input executable code to the browser's sink.

Sometimes applications require the use of dangerous methods such as document.write. In these cases, user-supplied input needs to be heavily sanitized through a combination of: JavaScript escaping HTML encoding URL encoding

As a general rule, all user-supplied input should be sanitized. We can sanitize the input from our example by using the node-esapi library recommended by OWASP. For example:

Content Security Policy

Another method for mitigating DOM XSS vulnerabilities is to utilize the Content Security Policy (CSP) security settings that are built into all modern browsers. In particular, using "nonce" will thwart attackers from being able to inject their own script tags, although this mitigation method is not sufficient to protect against some types of DOM XSS vulnerabilities; notably when the user input is injected into pre-existing script tags.

More information about CSP can be found here.

Keep learning