Topic 32

Cross-Site Scripting (XSS)

XSS

Cross-site scripting is injection into the browser: attacker-controlled input is reflected into a page without proper encoding, so the victim's browser runs the attacker's JavaScript in the context of the trusted site. That script can steal session cookies, act as the user, or rewrite the page — turning Meridian's own app against its users.

This topic covers the three XSS types, why output encoding (not input filtering) is the fix, and how Content Security Policy backstops it when an encoding bug slips through.

The Mechanism

Data that should be displayed as text is instead interpreted as HTML or JavaScript, because it was not encoded for the HTML context. The browser cannot tell the injected script from the site's own — both arrive in the trusted page — so it runs with the site's full trust, including access to the user's session. XSS is the app failing to keep user data as data when it renders it.

Stored, Reflected, and DOM-Based

Stored XSS persists — a malicious comment served to every viewer. Reflected XSS bounces off a parameter in a crafted link the victim clicks. DOM-based XSS happens entirely client-side, when JavaScript writes untrusted data into the page. Each needs the same encoding discipline, just in a different place — server-side for the first two, in the client code for the third.

The Fix: Context-Aware Output Encoding

Encode data for the exact context it lands in — HTML body, attribute, JavaScript, URL — because the same value that is safe in one context is dangerous in another. Modern frameworks auto-encode by default, and the bugs appear where developers bypass that: innerHTML, dangerouslySetInnerHTML, a template marked |safe. The rule is to let the framework encode and never hand it raw HTML built from user input.

What XSS Buys the Attacker, and CSP

XSS enables session hijacking if the cookie is not HttpOnly, performing actions as the victim, in-page credential phishing, and keylogging — which is why the Chapter 3 cookie flags and this chapter reinforce each other. A strict Content Security Policy restricts what scripts can run and where they can send data, containing XSS even when an encoding bug slips through. CSP is a backstop, not a substitute for encoding.

Output Encoding vs Input Sanitization for XSS

Output encoding — encode at the moment data enters a page, for that page's context; correct because the same data may be safe in one context and dangerous in another.

Input sanitization — strip "dangerous" markup on the way in; it loses information, breaks legitimate content, and misses context-specific cases. Encode on output; sanitize input only for rich text, with a vetted library like DOMPurify.

Common Mistakes
  • Building HTML by concatenating untrusted input or using innerHTML / dangerouslySetInnerHTML, bypassing the framework's auto-encoding.
  • Filtering input for <script> and assuming XSS is handled, when dozens of contexts and encodings evade naive filters.
  • Storing session tokens in JavaScript-reachable places (missing HttpOnly), so any XSS immediately steals sessions.
  • Shipping no Content Security Policy, so a single encoding slip becomes full script execution with no containment.
  • Treating DOM-based XSS as impossible because the server encodes output, when the flaw is in client-side JavaScript.
Best Practices
  • Rely on a framework that auto-encodes by context and never bypass it; where raw HTML is needed, sanitize with a vetted library.
  • Encode output for the specific sink — HTML, attribute, JavaScript, URL — treating each context as distinct.
  • Set HttpOnly, Secure, and SameSite on session cookies so XSS cannot trivially steal them (Chapter 3).
  • Deploy a strict Content Security Policy as defense in depth and monitor its violation reports.
  • Handle DOM-based XSS by encoding in client code and avoiding unsafe sinks like innerHTML.
Comparable toolsAuto-encoding React · Angular · Django templatesSanitize / policy DOMPurify · Content Security Policy · Trusted TypesTies to HttpOnly cookies (Ch 3)

Knowledge Check

Why does output encoding fix XSS better than filtering input for <script> tags?

  • Data safe in one context is unsafe in another; encode by sink
  • Input filtering is far too slow for busy, high-traffic websites
  • Encoding removes the need to authenticate users
  • Filtering <script> tags catches every possible XSS payload

What distinguishes DOM-based XSS from stored and reflected XSS?

  • It happens client-side when JS writes untrusted data
  • It requires the attacker to have a valid database account
  • It only affects sites without HTTPS
  • It is the only XSS type that cannot steal cookies

What role does a Content Security Policy play against XSS?

  • A backstop limiting what scripts run and where data goes
  • It is the primary fix, replacing the need to encode output
  • It encrypts the page so scripts cannot read it
  • It blocks all JavaScript on the site unconditionally

You got correct