Blog

Understanding cross-site scripting (XSS) attacks

XSS attacks are not to be taken lightly. Learn what XSS is, the different types of attacks, and how you can defend against them.


Cross-site scripting (XSS) is an attack in which an attacker injects malicious scripts into the code of a trusted website. From that point on, all user interactions with that website are compromised. This code is executed without the user’s awareness and can allow the attacker to steal sensitive data, hijack user sessions, or spread malware. Things can escalate if the victim user has privileged access to the application.

In this article, we will see the different types of cross-site scripting attacks, how they work, and how to defend against them.

How does Cross-site scripting work?

First, the attacker identifies its target. The targets are always websites that accept user input, like a search bar. If a website accepts user input and doesn’t sanitize it before rendering it but trusts the user instead, it is vulnerable to XSS attacks.

The way the attack is executed changes depending on the type of attack, but more often than not, it goes as follows. Once the target is identified, the attacker injects the malicious script, which, more often than not, involves JavaScript. The script can be injected as a comment or any other user-generated content that will be displayed to other users, like an image. If the image has an error on purpose, its onerror attribute will be invoked, which, for example, can send a request containing the user's cookie to the attacker's server. Since the script runs within the user's browser in the context of the vulnerable site, it can potentially access any cookies, session tokens, or other sensitive information that the browser holds for that site and send them to the attacker.

The malicious script execution can be triggered in various ways, such as when the page loads or when a user hovers over specific webpage elements like links.

Attackers can also attack by modifying a request. If the website is vulnerable to XSS attacks, the user-supplied input executes as code.

Let’s see in more detail how each type of XSS attack works.

Reflected XSS

Reflected XSS is also known as Non-persistent XSS or Type I. It's the most common type of XSS attack where the input is reflected back in the response.

The victim is tricked into clicking a link containing the malicious payload. Attackers use malicious links, phishing emails, and other social engineering techniques to trick the victim into making a request to the server. Once the link is clicked, the payload is sent to the vulnerable website, which then reflects the attack back to the user's browser, where the malicious script is executed.

Due to its non-persistent nature, the attack doesn't affect other users of the site.

Stored XSS

Stored XSS is also known as Persistent XSS or Type II. It's the most dangerous type of XSS attack because it affects all users of the compromised app.

The malicious script is injected directly into the website's database through an input mechanism like a form. The script is then rendered within a web page. If there is no output encoding or sanitization, when other users visit the page, they unknowingly load and execute the malicious script in their web browser. Unlike a reflected attack, where the script is activated after a link is clicked, a stored attack only requires that the victim visit the compromised web page.

A classic example is the comment section of a website. If the attacker manages to inject some JS as part of a comment, which gets stored in the database, then whoever sees the comment gets infected automatically. If you want to see an example of what that might look like, check out Chat hacked live by XSS/HTML code injection.

DOM-based XSS

DOM-based XSS is also known as Type 0. This type of XSS attack takes advantage of the Document Object Model (DOM) and takes place exclusively in the browser. The malicious payload is never sent to the server. This makes it even more difficult to detect.

This type of attack happens within the victim's browser by manipulating the DOM. This means that the page itself (i.e., the HTTP response) does not change, but the client-side code contained in the page executes differently due to the malicious modifications that have occurred in the DOM environment.

DOM-based XSS is possible if the web application writes data to the DOM without proper sanitization.

Mutation-based XSS

Mutation-based XSS, or mXSS, takes advantage of how HTML is handled, which makes it dangerous even if strong filters, like HTML sanitizers, are in place.

In this attack, the browser changes the user input in some way before inserting it into the DOM. HTML is a syntax-tolerant language that might change when parsing, and mXSS can take advantage of that by providing a payload that seems innocent initially when parsing (during the sanitization process) but mutates it to a malicious one when re-parsing it (in the final stage of displaying the content).

How to prevent cross-site scripting attacks

  • Validate and sanitize user input: We cannot stress this enough: never trust user input. In order for an XSS attack to be successful, an attacker must be able to insert and execute malicious content in a webpage. Thus, all variables in a web application need to be protected. You should always sanitize and validate input and reject anything unexpected. some text
    • Check for the expected format: An age field should only contain numbers. If that’s not the case, reject the input.
    • Use trusted libraries to sanitize input: Use a library that will strip dangerous HTML and return a safe string of HTML. An example is DOMPurify. This library sanitizes the DOM Tree by walking through all elements and HTML attributes and deleting all nodes that are not in the allow-list.
  • Use modern web frameworks: Applications built with modern web frameworks have fewer XSS bugs because these frameworks help mitigate them. However, it is critical to know how your framework prevents XSS and if it has gaps that you should address.
  • Use safe HTML attributes: safe HTML attributes treat variables as text and will never execute them. Try to refactor your code to remove references to unsafe attributes like innerHTML and instead use textContent or value. For a list of safe attributes, see Safe Sinks.
  • Use output encoding: When you need to safely display data exactly as a user types it in, output encoding is recommended. Variables should not be interpreted as code instead of text.
  • Content Security Policy: CSP is an allowlist that prevents content from being loaded. It works by restricting the resources (such as scripts and images) that a page can load and restricting whether a page can be framed by other pages. To enable CSP, a response needs to include an HTTP response header called Content-Security-Policy with a value containing the policy. If you choose to implement this, check the OWASP CSP Cheat Sheet.
  • Use the HttpOnly and Secure attributes on cookies: Mitigate damages in case of an attack by using the HttpOnly and Secure attributes. some text
    • Setting the HttpOnly flag on a cookie prevents it from being accessed by JavaScript.
    • The Secure flag ensures that the cookie can only be transmitted over secure HTTPS connections.
  • Use appropriate response headers: Use the Content-Type and X-Content-Type-Options headers to prevent XSS in HTTP responses that aren't intended to contain any HTML or JavaScript.
  • Do penetration testing: Even if you’ve checked all the boxes, the only way to be confident that your website is safe is to have penetration testers implement real-world attack scenarios against it.

For more details and a complete list of the things you must check to prevent XSS attacks, check the XSS Prevention Cheat Sheet by OWASP.

In this article

This site uses cookies to improve your experience. Please accept the use of cookies on this site. You can review our cookie policy here and our privacy policy here. If you choose to refuse, functionality of this site will be limited.