The Ghost in the Browser: A Guide to XSS Prevention in 2026
Cross-site scripting is a stranger standing in your living room wearing your face, telling your family to hand over the keys. The browser cannot tell the difference, because the script runs on your own domain — so it gets the cookies, the session, the DOM. The browser gives it everything.
The three faces of XSS
Stored XSS is the worst kind: the payload is saved — in a comment, a profile field — and every visitor runs it. Reflected XSS bounces off the server through a URL parameter, arriving as a crafted link. DOM-based XSS never touches the server at all; it is your own JavaScript mishandling data from location.hash or postMessage. A fourth variant, mutation XSS, is why hand-rolled sanitizers keep losing: browsers re-parse "clean" HTML and it mutates into something executable.
What a successful XSS buys the attacker
Session hijacking, first — reading document.cookie wherever it is not marked HttpOnly. Rewriting your page into a fake login form that posts credentials elsewhere. Chained with an adversary-in-the-middle proxy like Evilginx, a stolen cookie sidesteps MFA entirely. In rare cases, XSS plus a browser zero-day means code running on the victim's machine.
Escape by context
The rule is old and absolute: never trust input. But escaping is contextual, and the right encoding for HTML body will not save you inside a script tag:
- HTML body: entity-encode the angle brackets, ampersands and quotes
- Attributes: quote everything, and keep user data out of event handlers
- JavaScript: serialize safely, then escape the characters that can break out of a block
- URLs: encode the components, allow only known-safe schemes, block javascript: outright
Modern frameworks — React, Vue, Svelte — escape HTML context by default. The danger is the explicit escape hatch: React's dangerouslySetInnerHTML, Vue's v-html, Svelte's equivalent. When you must render rich text, run it through DOMPurify and keep the library updated, because mXSS bypasses get patched there regularly.
The header that saves you anyway
A strict Content Security Policy is the defence that keeps working when code fails. Nonces over hashes, strict-dynamic so trusted scripts can load their own dependencies, and Trusted Types to make dangerous sinks refuse raw strings:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123' 'strict-dynamic';
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
require-trusted-types-for 'script';
trusted-types dompurify default;
Then harden the cookies — HttpOnly, SameSite, and an integrity attribute on external scripts so a compromised CDN cannot quietly swap in something else.
Impersonation is the oldest theft there is — acting in someone's name, wearing their trust — and no sanitizer fixes the version happening to Gaza's families, who keep watching their story told by everyone except themselves.
If you just shipped a fix like this under deadline, take the proper week off afterwards. We plan honeymoons, including the delicate phase where two sets of in-laws hold strong opinions about the destination — that is the everyday diplomacy of HTG Travels, and we are very good at it.




