RestingOwl owl logo RestingOwl

What Is Cross-Site Scripting (XSS)?Types, Impact & Prevention

Quick Answer: Cross-site scripting (XSS) is an injection attack where malicious JavaScript is inserted into a web page and executed in another user's browser. The attacker's script runs with the victim's session privileges: enabling session hijacking, credential theft, and account takeover. Prevention: always encode output, set a Content Security Policy, and never trust user-supplied data as safe HTML.

XSS has appeared in the OWASP Top 10 in every edition since the list was created. It is consistently one of the most exploited vulnerability classes in web applications: not because it is new or exotic, but because it is easy to introduce, often subtle, and the consequences of exploitation are severe. A real-world example: in May 2026, CISA confirmed active exploitation of an XSS flaw in Microsoft Exchange's Outlook Web Access, giving attackers full access to authenticated email sessions. Read the full incident report.

What Is XSS? A Plain-English Explanation

A web application is vulnerable to XSS when it takes untrusted input: from a user, a URL parameter, a database, or any external source: and includes it in a web page without properly encoding it first. The browser has no way to distinguish between JavaScript your application intentionally served and JavaScript an attacker slipped in through unsanitized input. It runs both.

The attacker's goal is to make their script execute in the browser of a user who is logged in to the vulnerable application. Once that happens, the script runs with the full privileges of that user's session: it can read cookies, make API requests on the user's behalf, capture keystrokes, and exfiltrate data. From the browser's perspective, the script is part of the legitimate page.

The Three Types of XSS

TypeHow It WorksWhere the Script LivesWho Is Affected
Stored (Persistent)Attacker injects script into the database via a form input. Every user who loads the page containing that data executes the script.Server-side databaseAll users who view the affected content
Reflected (Non-Persistent)Attacker crafts a URL containing a script payload. When a victim clicks the link, the server reflects the payload back in the response page.The URL itselfOnly users who click the malicious link
DOM-BasedScript never touches the server. The vulnerability is in client-side JavaScript that writes user-controlled data directly to the DOM without encoding.The browser's DOMUsers who load a page where the DOM manipulation occurs

Stored XSS is the most dangerous: one successful injection can affect every user who views the compromised content, continuously, until the payload is discovered and removed. A stored XSS in a comment field, a user profile, or a support ticket system can persist for days or weeks.

What Can an Attacker Do With XSS?

The impact depends on what the application does and what privileges the victim holds: but the attack surface is broad:

  • Session hijacking: Steal the victim's session cookie and use it to authenticate as them from a different browser. If the cookie lacks the HttpOnly flag, document.cookie returns it directly.
  • Account takeover: Use the victim's authenticated session to change their email address or password, locking them out permanently.
  • Credential harvesting: Inject a fake login prompt over the legitimate page and capture credentials as the user types them.
  • Data exfiltration: Read private data visible on the page and send it to an attacker-controlled server via a background HTTP request.
  • Malware delivery: Redirect the browser to a malicious download or exploit kit.
  • Privilege escalation: If the victim is an administrator, the script can perform administrative actions: creating users, changing configurations, or accessing privileged data.

XSS vs CSRF: What Is the Difference?

XSS and CSRF (Cross-Site Request Forgery) are frequently confused. They are different attacks with different mechanisms and different defenses.

DimensionXSSCSRF
What the attacker controlsJavaScript executing in the victim's browserHTTP requests made from the victim's browser
Where the malicious code runsInside the vulnerable application's originFrom a different origin (cross-site)
Bypasses same-origin policy?Yes: script runs within the legitimate originNo: exploits the browser's automatic credential sending
Can read response data?Yes: full access to the DOM and responsesNo: can only trigger requests, not read results
Primary defenseOutput encoding and Content Security PolicyCSRF tokens and SameSite cookies
Which is worse?Generally worse: far broader capabilitiesMore limited but still serious

An important relationship: XSS can bypass CSRF defenses. If an attacker has XSS execution, they can read the CSRF token from the page and include it in forged requests. This is why fixing XSS takes priority: a successful XSS attack can invalidate most other controls on the page.

How to Prevent XSS in Your Application

XSS prevention requires defense in depth: multiple layers, because a single missed encoding point can re-open the vulnerability. OWASP defines a hierarchy of controls:

1. Output Encoding (Primary Defense)

Encode all user-controlled data before inserting it into the page. The encoding context matters: HTML, JavaScript, CSS, and URL contexts each require different encoding. Inserting text into HTML? HTML-encode it. Inserting into a JavaScript string? JavaScript-encode it. Using the wrong encoding for the context leaves the vulnerability open.

2. Content Security Policy (CSP)

A Content Security Policy is an HTTP response header that tells the browser which scripts are allowed to execute. A strict CSP: blocking inline scripts and restricting script sources to known origins: dramatically reduces the impact of an XSS vulnerability even when one exists. CSP is a critical mitigation layer, not a replacement for encoding.

3. HttpOnly and Secure Cookie Flags

Setting HttpOnly on session cookies prevents JavaScript from reading them via document.cookie. This blocks the most common XSS exploit: session cookie theft: even when the attacker achieves script execution. Always set HttpOnly and Secure on any cookie that should not be accessible to client-side scripts.

4. Avoid Dangerous APIs

Several JavaScript APIs are inherently XSS-risky because they interpret strings as HTML or script. Avoid using innerHTML, outerHTML, document.write(), and eval() with any user-controlled data. Use textContent instead of innerHTML when you only need to insert text. In frameworks like React, Angular, and Vue, prefer the framework's native data binding which encodes automatically.

XSS Prevention Checklist

  • HTML-encode all user-controlled data before rendering it in HTML context
  • JavaScript-encode data inserted into JavaScript strings
  • Use textContent instead of innerHTML wherever possible
  • Implement a strict Content Security Policy and avoid unsafe-inline
  • Set HttpOnly and Secure flags on all session cookies
  • Set SameSite=Strict or SameSite=Lax on cookies
  • Validate and sanitize HTML input on the server side if you must accept rich text (use an allowlist-based sanitizer such as DOMPurify)
  • Scan your codebase for direct DOM manipulation with user-controlled data
  • Use framework-native data binding rather than raw DOM API calls
  • Add XSS scanning to your CI pipeline and use automated DAST tooling

Why XSS Is Still in the OWASP Top 10

XSS has been in the OWASP Top 10 since the list began. In the 2021 edition it sits within the broader 'Injection' category (A03). Despite decades of awareness, XSS persists for several structural reasons:

  • Modern web applications are complex: a single missed encoding point in thousands of output locations is enough
  • Third-party scripts, advertising networks, and analytics tools expand the attack surface beyond the application's own code
  • DOM-based XSS is harder to detect in code review and is missed by many server-side security scanners
  • Developer frameworks sometimes introduce unexpected unsafe APIs or bypass encoding in edge cases
  • The attack is invisible to the user: no error, no warning, no indication that anything is wrong

The active exploitation of the Microsoft Exchange XSS vulnerability in 2026 is a reminder that XSS is not a theoretical concern. It is exploited in production systems, at scale, against real users: including in enterprise software that has been maintained for decades. The fundamentals of prevention have not changed: encode your output, set your CSP, and never trust data from outside your application.

References

  1. 1OWASP XSS Prevention Cheat Sheet
  2. 2OWASP DOM-based XSS Prevention Cheat Sheet
  3. 3CISA: Microsoft Exchange XSS Flaw Actively Exploited: RestingOwl News

Q&A Section

No. Both are injection attacks: malicious data treated as code: but they target different layers. SQL injection targets the database by inserting SQL commands into a query. XSS targets the browser by inserting JavaScript into a web page. The defenses are also different: parameterized queries for SQL injection, output encoding and CSP for XSS.
Largely yes: for data bound through the framework's normal templating. React's JSX encodes values by default; Angular's template binding encodes HTML. However, all three frameworks expose escape hatches (dangerouslySetInnerHTML in React, bypassSecurityTrustHtml in Angular) that disable encoding. Using these with user-controlled data immediately reintroduces XSS. Framework protection is not unconditional.
Input validation checks whether incoming data matches expected patterns: rejecting inputs that look malicious. Output encoding transforms data into a safe representation before inserting it into the page. OWASP recommends output encoding as the primary defense because it works regardless of what input validation did or did not catch. Input validation is a useful secondary layer but should never be the sole XSS defense.
Multiple approaches: automated DAST tools (OWASP ZAP, Burp Suite) scan for common XSS patterns. Manual testing involves inserting test payloads like <script>alert(1)</script> into every user-controlled input and checking whether the script executes. Code review focuses on finding all places where user-controlled data reaches output functions. Browser developer tools help trace DOM manipulation. No single method catches everything: use all three.
Copied!