What is XSS (Cross-Site Scripting)? How it works and how to prevent it
Cross-Site Scripting (XSS) lets an attacker run their own JavaScript in another user's browser. This guide explains how the three types work and the defenses that stop them.
On this page
- How XSS works
- The three types of XSS
- Reflected XSS
- Stored XSS
- DOM-based XSS
- What an attacker can do
- How to prevent XSS
- 1. Contextually aware output encoding
- 2. Avoid raw-HTML and unsafe sinks in client code
- 3. Context-sensitive input validation
- 4. Use the HTTP security headers and frameworks
- 5. Test for XSS
- Security in a larger picture
- FAQ
- What is XSS (Cross-Site Scripting)?
- What are the three types of XSS?
- Can XSS steal passwords?
- How do I check if my site is vulnerable to XSS?
- Summary
Cross-Site Scripting (XSS) is a type of injection attack in which an attacker injects a malicious script into an otherwise trusted website. When the page runs, the script executes in the victim's browser with the trust and privileges of that site — the victim's origin, cookies, session, and ability to read and modify the page. Because the browser thinks the script came from a trusted source, it grants it the same access as legitimate code.
XSS is one of the oldest and most persistent web vulnerabilities. It sits in the injection category of the OWASP Top 10, and it can range from an annoyance to complete account compromise. This guide explains how the three main types work, what an attacker can do with them, and the defenses that reliably stop them.
How XSS works
XSS happens when an application takes input from an untrusted source and includes it in the HTML or JavaScript it sends to a browser without safely encoding or validating it. The browser cannot tell that the injected fragment is not part of the site's own code, so it executes it with the same origin and privileges.
For example, consider a search page that echoes the query back, like this:
<h2>Results for: <user input></h2>
A normal request produces Results for: node. But an attacker who crafts a request such as ?q=<script>…</script> makes the application write an actual <script> tag into the page, which the browser then executes.
Because the injected script runs inside the trusted origin, it can access the site's cookies and session tokens, read and modify the DOM, make authenticated requests to the site's APIs, or rewrite the page to phish for credentials. The browser's Same-Origin Policy offers no protection here — the code is running on the inside with the site's own privileges.
The three types of XSS
XSS is usually grouped into three types, separated by how the payload reaches the victim.
Reflected XSS
Reflected (also called non-persistent or Type-I) XSS happens when user input is immediately echoed back by the server in a response — for example in a search result, an error message, or another response that includes part of the request — without being made safe to render. The payload lives in the request itself and never touches the server's storage.
Reflected XSS needs the victim to do something: click a crafted link, submit a specially crafted form, or visit a malicious page that triggers the request. The attacker typically delivers the URL through email, social media, or another site.
Stored XSS
Stored (also called persistent or Type-II) XSS happens when the injected script is permanently stored on the target server — in a database, a comment field, a message forum, a visitor log, or a user profile — and is later served to every user who views that data. Because no extra interaction with the victim is needed beyond visiting the page, stored XSS is generally considered the more dangerous of the three.
DOM-based XSS
DOM-based XSS is a client-side problem. The server's response is the same for every user, but client-side JavaScript copies an attacker-controlled source — such as location.hash, location.search, or document.referrer — into a dangerous sink such as innerHTML or document.write. The payload never leaves the browser, so the server never sees it and cannot sanitize it at the response level. Frameworks can open the same hole when code uses raw-HTML insertion such as dangerouslySetInnerHTML (React) or v-html (Vue).
What an attacker can do
The consequences of XSS are similar regardless of which type it is — the difference is only in how the payload arrives. A successful exploit can:
- Steal session tokens and cookies, letting the attacker impersonate the victim.
- Read sensitive data held in the page or sent to the site's APIs.
- Rewrite the page to show fake login forms or phishing content.
- Make authenticated requests on the victim's behalf (which also bypasses CSRF protections).
- Install a keylogger or other script that records what the victim types.
A "read-only" or brochure-style site is not immune — reflected XSS can still appear in search and error responses.
How to prevent XSS
Prevention follows a defense-in-depth approach, because no single control is sufficient on its own.
1. Contextually aware output encoding
The primary defense is to encode untrusted data in the correct way for the context where it is rendered — HTML, an HTML attribute, JavaScript, CSS, or a URL all need different escaping rules. A framework that auto-escapes by default, used consistently, removes most of the risk. The OWASP XSS Prevention Cheat Sheet documents the correct encoding for each context.
2. Avoid raw-HTML and unsafe sinks in client code
On the client side, prefer textContent and safe DOM methods over innerHTML, outerHTML, document.write, and eval. If you must insert HTML, sanitize it with a tested allow-list sanitizer such as DOMPurify, and never funnel location or referrer data into a sink. Treat framework escape-hatches like dangerouslySetInnerHTML and v-html as the security-sensitive paths they are.
3. Context-sensitive input validation
Validate input against an allow list of what is expected (for example, only alphanumeric characters for a username). Validation alone does not prevent XSS — it must be combined with encoding — but it reduces the chance of dangerous characters reaching a render path.
4. Use the HTTP security headers and frameworks
A modern Content-Security-Policy (CSP) that restricts where scripts can load from is a strong second layer: even if a payload slips through, the browser refuses to run it. Frameworks with built-in auto-escaping and template systems also prevent most injection by default, provided developers do not bypass them with raw-HTML APIs.
5. Test for XSS
Treat XSS as a class of bug to hunt for, not a one-time fix. Automated scanners, manual testing, and source review of every place user input reaches output should be part of the development workflow.
Security in a larger picture
XSS is one member of the broader injection family, which also includes SQL injection and command injection. They share the same root cause — untrusted data being treated as executable code — and the same first line of defense: keep data separate from the instructions that process it, and encode or validate at every boundary. For related concepts, see our guides on SQL injection and HTTPS.
FAQ
What is XSS (Cross-Site Scripting)?
XSS is an injection attack in which malicious script is injected into a trusted website and executed in another user's browser with the site's origin and privileges. It can steal cookies and session tokens, read page data, modify the page, or make authenticated requests on the victim's behalf.
What are the three types of XSS?
Reflected XSS echoes request input straight back in a response without safe encoding; stored XSS persists the payload on the server and serves it to every visitor; DOM-based XSS happens entirely client-side when JavaScript copies an attacker-controlled source into a dangerous sink like innerHTML.
Can XSS steal passwords?
XSS can steal anything the page can access, including submitted form values and entered credentials. An attacker can rewrite a page to show a fake login form, or install a script that records keystrokes, then capture the victim's password when it is typed.
How do I check if my site is vulnerable to XSS?
Look for every place where user input reaches the HTML, an attribute, a script, or a URL, and confirm it is encoded for that context. Common targets are search and error responses (reflected), comments and profiles (stored), and client-side code that writes to innerHTML or similar sinks (DOM-based). Automated scanners and manual testing help surface these paths.
Summary
Cross-Site Scripting is an injection vulnerability where attacker-controlled script runs in a victim's browser with the trust of a legitimate site. It is classified into reflected, stored, and DOM-based types, which differ only in how the payload reaches the victim. In every case it can steal sessions, read sensitive data, and act as the victim. The reliable defenses are contextually aware output encoding, avoiding raw-HTML and unsafe client-side sinks, allow-list input validation, strong Content-Security-Policy headers, and regular testing. Because XSS is easy to trigger and its impact can be severe, any application that renders user input should treat prevention as mandatory, not optional.
Sources
- OWASP — Cross Site Scripting (owasp.org/www-community/attacks/xss
- CC BY-SA 4.0)
- OWASP — Types of Cross-Site Scripting (owasp.org/www-community/Types_of_Cross-Site_Scripting
- CC BY-SA 4.0)
- OWASP — XSS Prevention Cheat Sheet (cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- CC BY-SA 4.0)
- Wikipedia — Cross-site scripting (en.wikipedia.org/wiki/Cross-site_scripting
- CC BY-SA 4.0)
Share this guide
Related guides
- What is CSRF (Cross-Site Request Forgery)? How it works and how to prevent it
Cross-Site Request Forgery (CSRF) tricks a logged-in browser into sending unwanted requests to a trusted site. This guide explains how the attack works and the defenses that stop it.
- What is authentication? Passwords, biometrics, SSO, and modern methods explained
Authentication is the process of verifying who you are. Learn how passwords, multi-factor authentication, biometrics, SSO, OAuth, and password managers work — and which methods offer the best protection for your application.
- What is SQL injection? How it works and how to prevent it
SQL injection is one of the most common web vulnerabilities — this guide explains how it works, the main attack types, and the secure coding practices that prevent it.