blueredix logo
info vuln-class-xss

Cross-Site Scripting (XSS), in plain English

XSS lets an attacker run their own JavaScript in another visitor's browser session on your site. From there: account takeover, stolen passwords, fake login screens.

What this is

Cross-Site Scripting (XSS) is a category of website bug where text controlled by an attacker ends up displayed on your page in a way the browser interprets as code rather than as content. The text becomes JavaScript, the JavaScript runs inside your visitor’s browser, and from your visitor’s perspective the code is part of your site — same domain in the address bar, same lock icon. The attacker gets to do anything your visitor’s logged-in session can do.

The mistake behind every XSS bug is the same: input arrived from somewhere and got written into the page without being properly treated for the place where it ended up. The variations differ only in where the bad input came from.

Three flavours

Reflected XSS

The attacker crafts a URL with the malicious payload in it, sends the URL to a victim (email, chat, ad), and the application echoes the payload back into the response page. Search forms and error messages are common sources. Reach is one victim per click — but that’s enough for targeted phishing.

Stored XSS

The malicious payload is written into the application’s database and served back to anyone who later views the affected page. Forum posts, comments, usernames, profile bios, support-ticket messages, product reviews — any field where one user types text that other users later see. One attack, many victims.

DOM-based XSS

The bug is purely in your frontend code: a JavaScript file in the page reads attacker-controlled input from somewhere (location.hash, postMessage, the URL query string) and inserts it into the page in a way that runs script. Your server may be entirely innocent — the bug lives in the client-side code.

Why it matters

XSS gives the attacker the visitor’s session at the moment of execution. The concrete consequences:

  • Account takeover. Read every cookie not specifically marked off-limits to JavaScript. Even cookies that are marked off-limits don’t fully protect — the script can simply submit requests on the user’s behalf inside the open session.
  • Form-data theft. Hook every form submission, exfiltrate every password, payment detail, or message before the form reaches your server.
  • Phishing in place. Replace the page contents with a fake login screen that looks identical to your real one. The address bar still reads your-domain.example; the lock is still green.
  • Worm-style spread. A stored XSS in a social feature can post itself everywhere the victim has access — see Samy on MySpace and the Twitter retweet worms.

In a CMS or admin panel, XSS in an admin’s session is, in practical terms, full administrative control of the site.

How it gets fixed

XSS is fixed by encoding the output for where it lands, not by filtering the input. The same string is safe in one context and dangerous in another.

Output context What’s needed
HTML body text Replace <, >, &, ", ' with their HTML-safe equivalents
HTML attribute value HTML-encode and quote the attribute
JavaScript string literal JS-escape, or better, JSON-encode
URL parameter URL-encode the value
CSS context Avoid; if unavoidable, strict allowlist

In practice, modern frameworks do the right thing by default:

  • React, Vue, Svelte, Angular automatically escape text in templates. The dangerous functions are explicitly named (dangerouslySetInnerHTML, v-html, [innerHTML]) so an audit can find them.
  • Templating engines (Jinja, Twig, ERB, Liquid) escape by default; the risky escape hatch is {{ raw }} / safe / similar.
  • Backend code that writes HTML by hand is the highest-risk area; every out.write("<div>" + x + "</div>") is a potential XSS waiting for the right input.

Layered defences for when something slips through anyway:

  • A Content Security Policy with nonces or hashes — see our CSP article. With CSP in place, a successful XSS payload still struggles to load attacker- controlled scripts, exfiltrate to attacker-controlled hosts, or open new framed UI. It doesn’t stop XSS from existing, but it caps the damage.
  • HttpOnly + Secure + SameSite cookies for sessions. A session cookie with these attributes can’t be read by JavaScript and isn’t sent on cross-site requests in most cases. Doesn’t cure XSS but reduces its leverage.

How blueredix surfaces XSS

The scanner doesn’t actively inject XSS payloads against your live application — that’s reserved for authorised testing. What we flag:

  • CVEs in third-party software (admin panels, CMSs, plugins) with XSS in the description.
  • JavaScript libraries with documented XSS bugs and a fixed version available.
  • Header tells: missing Content-Security-Policy, missing X-Content-Type-Options: nosniff, cookies missing the HttpOnly flag — each of which makes XSS easier to exploit.

A real test of your own code’s XSS resistance is a manual review or a penetration test, not an automated black-box scan.

Further reading