The Three Types of Cross Site Scripting You Must Know

When an attacker injects malicious scripts into a web page viewed by other users, that’s Cross Site Scripting, or XSS. It’s not one single trick. It breaks down into three distinct attack types, each with its own method and countermeasure. I’ve seen them all in the wild, from sloppy comment forms to complex web applications. 

If you want to build things that last, you need to understand the different types of cross site scripting. Stick with me, and I’ll walk you through what they are, how they work, and, most importantly, how you stop them. Let’s get into it.

Three XSS Truths Every Developer Should Know 

Before exploring each type, here are the key lessons every developer should remember. 

  • Stored XSS is the most dangerous type, poisoning a website’s database to attack every future visitor.
  • Reflected XSS tricks a single user into clicking a booby-trapped link, with the attack bouncing off the server.
  • DOM-based XSS happens entirely in the user’s browser, manipulating the page’s structure without server interaction.

Understanding the Three Types of Cross Site Scripting 

An illustration of a web browser confused by malicious data within the classic types of cross site scripting. 

I remember the first time I saw a live XSS attack. It wasn’t in a lab. It was on a local artist’s forum, a simple guestbook page where visitors could leave notes. Someone had left a message that wasn’t a message at all, but a script tag. It didn’t do much, just popped up an alert box. But that alert box was a warning siren. 

It meant the site trusted raw user input, and that trust was a wide-open door. The web is built on a conversation between client and server, user and application. XSS exploits that conversation, turning a website’s own functionality against its users. It’s a betrayal of the basic contract of a webpage.

The core of the problem is context. A browser will execute JavaScript code it finds in a page. It doesn’t inherently know the difference between code you, the developer, wrote and code a malicious user submitted in a form field. If you don’t explicitly tell it, “this chunk of text is just data, not instructions,” the browser will run it. 

This confusion creates the space where all three types of XSS operate. They just deliver their malicious payloads in different ways.

Stored XSS: The Poison in the Well

This is the persistent one, the sleeper agent. An attacker submits a malicious script, and the application stores it. In a database, a comment thread, a user profile field. It saves it like any other piece of data. 

“Cross-site scripting (XSS) is a type of security vulnerability typically found in web applications.” Wikipedia

Then, later, when the application serves that page to other users, the script is delivered as part of the legitimate response and executes in their browsers. The damage isn’t a one-time thing. It’s served to every user who views the tainted content, sometimes for months.

The impact here is massive. It’s how you get website defacements, credential theft on a grand scale, or crypto-mining scripts running silently on thousands of visitors’ machines. I once audited a small e-commerce site where product reviews weren’t sanitized. 

A bad actor could have injected a script into a review for a popular product, and every customer reading reviews would have been hit. The fix wasn’t complex, but the oversight was catastrophic in potential. If you want a foundational breakdown of how these vulnerabilities operate, you can check out this cross-site scripting xss explainer. 

  • The attack is stored on the server (database, file system).
  • Victims retrieve the malicious script automatically when viewing the compromised page.
  • It has the widest, most lasting impact of all XSS types.

Stopping stored XSS is about defense at the point of entry and exit. You must validate and sanitize every piece of user input before it touches your database. But more crucially, you must encode that data when you output it back to the HTML page. 

This tells the browser, “This text is data, not code.” It’s a fundamental shift in thinking. You stop treating user data as safe HTML and start treating it as plain text that needs to be carefully placed into a web context.

Reflected XSS: The Mirror Trap

Credits: Edureka!

This type is non-persistent. It doesn’t live in your database, which highlights a core part of the stored vs reflected xss difference. Instead, the attack is reflected off the web server in an immediate response. 

The victim clicks. Their browser sends the script, embedded in the URL, to the vulnerable website. The website includes that script from the request directly into its response page, and the victim’s browser executes it.

It’s a mirror. The site takes the input and reflects it right back, unfiltered. A common place you’ll see this is in search results pages. Imagine a site that displays “You searched for: [user’s search term]” at the top of the page. 

If that search term isn’t encoded, and someone searches for <script>badCode()</script>, that script might run. An attacker would just need to get someone to click a link that performed that malicious search.

The payload is delivered via a single HTTP request. It requires social engineering to trick a user into clicking the link. The vulnerability is in how the server handles data in the request (URL parameters, form data).

The defense is similar to stored XSS but focused on output. Never, ever directly insert user-provided data from the URL or a POST request into your HTML response without proper context-aware encoding. 

It’s a simple rule that breaks the attack chain completely. The user might click the bad link, but if your code properly encodes the reflected value, it will appear as harmless text on the page, not executable code.

DOM-based XSS: The Client-Side Illusion

This is the trickster of the group. With stored and reflected XSS, the flawed logic is partly on the server. It sends the bad script down. DOM-based XSS is different. The server might send perfectly safe, static HTML. 

The vulnerability is in the client-side JavaScript. An attacker finds a piece of code that takes a value they can control (like a URL fragment after the #) and uses it unsafely to update the page’s Document Object Model (DOM).

Since it all happens in the browser, the malicious payload never touches the server. It makes it harder to detect with traditional server-side security tools, especially when defending against specific dom-based xss attack vectors. The attack manipulates the inner skeleton of the page after it’s already loaded. 

Think of a page that uses document.write or innerHTML to update content based on window.location.hash. An attacker crafts a URL where the hash contains a script. The victim’s browser processes the JavaScript, sees the hash, and writes it directly into the page’s body, executing the attack.

  • The entire attack executes in the victim’s browser.
  • The server response may be clean; the taint is in the client-side script logic.
  • It often involves sources like document.URL, location.hash, or user input passed to dangerous sinks like innerHTML.

Preventing this requires a shift to safe DOM manipulation methods. Avoid innerHTML when inserting plain text; use textContent instead. Be incredibly careful with sources of data that an attacker can control from the client side, like URL fragments. 

Use client-side encoding libraries designed for the specific context you’re writing to, whether it’s an HTML attribute, CSS, or a JavaScript string. It’s about writing your front-end code with the same suspicion you apply to your back-end.

A Practical Comparison

Infographic detailing the key takeaways, impacts, and defenses for the types of cross site scripting.

To see the flow, it helps to lay them side by side.

Attack TypeWhere the Malicious Script LivesHow it Reaches the VictimPrimary Defense Focus
Stored XSSOn the server (database).Served automatically in the page content.Output encoding & input validation.
Reflected XSSInside a malicious URL.User clicks the attacker’s link.Context-aware output encoding of request data.
DOM-based XSSInside a malicious URL (client-side part).User clicks the attacker’s link.Safe DOM APIs & client-side encoding.

The table shows the path. Stored attacks are an infection. Reflected attacks are a reflected beam. DOM-based attacks are a sleight of hand in the user’s own machine. Your job is to build barriers for each path.

“Cross-site scripting (XSS) is one of the major threats menacing the privacy of data and the navigation of trusted web applications.”Hannousse, A., Yahiouche, S., & Nait Hamoud, N. (2022),

Building Your Defense: It’s About Habits

2D vector graphic showing input validation and encoding defenses against various types of cross site scripting. 

So how do you actually stop these? You don’t need a magic library, though good tools help. You need a set of ingrained habits, what we call secure coding practices. It starts with mindset. Assume all input is tainted. 

Every single string from a user, a URL, a third-party API, even another part of your own system if you’re not careful, should be considered potentially hostile until proven otherwise.

We make this real by adopting a few non-negotiable rules. First, validate input on the server for type, length, and format. A comment field shouldn’t accept ten thousand characters of script-looking code. Second, and this is the most critical universal fix, always encode data on output. 

Encoding is the process of converting characters like < and > into their safe equivalents (&lt; and &gt;). This ensures they are displayed as text, not interpreted as HTML tags. Use well-established libraries for this; don’t try to roll your own escape functions.

For modern JavaScript-heavy applications, consider frameworks that automatically provide contextual output encoding, like React’s JSX or Vue’s templating. They structure the code in a way that makes the dangerous patterns less common. Finally, implement a Content Security Policy (CSP) header. 

This is your last line of defense. It tells the browser which sources of scripts, styles, and other resources are allowed to execute. Even if an attacker gets some malicious script into your page, a strong CSP can prevent the browser from running it.

FAQ

Which Type of XSS Is the Most Dangerous?

Stored XSS is generally considered the most dangerous because the malicious script is saved on the server and automatically delivered to every user who visits the affected page. A single successful injection can impact hundreds or even thousands of visitors before it is detected and removed.

How Is DOM-Based XSS Different from Other XSS Attacks?

Unlike Stored and Reflected XSS, DOM-based XSS occurs entirely within the user’s browser. The server may never process or store the malicious payload. Instead, vulnerable client-side JavaScript reads attacker-controlled data and inserts it into the page in an unsafe way.

Can Modern JavaScript Frameworks Prevent XSS?

Frameworks such as React, Angular, and Vue provide built-in protections by automatically escaping user-generated content in many situations. However, developers can still introduce XSS vulnerabilities when using unsafe functions, rendering raw HTML, or bypassing the framework’s security features.

What Is the Best Defense Against All Types of XSS?

The most effective approach is layered security. Developers should validate input, encode output, use safe DOM APIs like textContent, implement a strong Content Security Policy (CSP), and regularly test applications for vulnerabilities. No single control can stop every XSS attack on its own.

Moving Beyond the Three Types of Cross Site Scripting

Understanding the three types of cross site scripting is only the beginning. Real protection comes from daily secure coding habits, using safe DOM methods, validating input, encoding output, and reviewing code with security in mind. 

The most resilient applications are built by developers who make security part of every decision. If you want hands-on experience applying these practices, the Secure Coding Practices Bootcamp provides practical training on OWASP Top 10 risks, authentication, encryption, input validation, and more through real-world coding exercises. 

References

  1. https://en.wikipedia.org/wiki/Cross-site_scripting 
  2. https://arxiv.org/abs/2205.08425 

Related Articles