Cross-Site Scripting (XSS)

Free this month Medium Course Online Avg. time 35 min Solved by 0 2 keys · 50 pts Injection

If SQL injection is input becoming code inside a query, cross-site scripting is input becoming code inside a web page. In this exercise you will see how a comment box can run your JavaScript in a victim's browser, why that is so dangerous, the three flavours of XSS and what tells them apart, and the output-encoding fix that stops all of them.

Skills covered: XSSInjection
Log in or create a free account to submit keys and track your progress.

What you will learn

  • Explain what XSS is and what kind of code it runs
  • Name the three types of XSS and what distinguishes them
  • Explain why a stolen session cookie lets an attacker become you
  • Explain how output encoding and HttpOnly cookies defend against XSS

Before you start

These exercises cover what this one builds on.

1 Your code in someone else's browser

Cross-site scripting, mercifully shortened to XSS, is a flaw where a site takes your input and puts it into a page *without cleaning it*, so any script you sneaked in runs in whoever views that page. The code that runs is JavaScript — the language every browser executes.

How an XSS payload reaches a victim
How an XSS payload reaches a victim

A browser is supposed to run only the JavaScript the site's developers wrote. XSS breaks that promise: the attacker gets *their* JavaScript onto the page, and the browser cannot tell the difference. It trusts every script the page contains equally, because it has no way to know one came from the developer and one came from a stranger's comment.

The mental model is the comment box. You are meant to type words. If you type <script>alert(1)</script> and the site displays it back raw, the browser does not show those characters — it treats them as real code and runs them. That confusion between "content to display" and "code to run" is the entire vulnerability, and it is the exact same data-versus-code confusion behind SQL injection, just in a different destination.

2 Why it is dangerous

"A script popped up a box — so what?" The danger is not the box; it is *where* the script runs and *with whose authority*.

The attacker's JavaScript runs inside the victim's browser, on the real site's page, with all the trust the browser gives that site. So it can do anything the victim could do on that site:

Stealing a session cookie with XSS
Stealing a session cookie with XSS
  • Steal the session cookie. As you will remember, the session cookie *is* the user's logged-in identity — the wristband the server handed them at login. JavaScript on the page can read document.cookie and send it to the attacker's server. With that cookie, the attacker loads the site and *is* the victim, no password required.
  • Act as the user, silently. Change their email, move their money, post as them — all through the page they already trust.
  • Rewrite the page. Replace the real login form with a fake one that sends passwords to the attacker.

So the usual prize of an XSS is the session cookie, because capturing it is the quiet way to become someone else. Everything else is a bonus.

3 The three flavours

XSS comes in three types. What tells them apart is simply where the malicious payload lives.

Reflected, stored and DOM-based XSS
Reflected, stored and DOM-based XSS
  • Reflected XSS. The payload rides in the request — usually in a URL parameter — and the server immediately "reflects" it back in the response. It only fires for someone who follows the attacker's crafted link. Think of a search page that puts your search term straight into the results: a link with a script in the search term attacks whoever clicks it.
  • Stored XSS. The payload is *saved* on the server — in a comment, a profile bio, a product review — and then served to everyone who views that content. No special link needed; the trap sits there and fires for every visitor. This is the most dangerous kind precisely because it reaches many victims automatically.
  • DOM-based XSS. The flaw is in the site's own JavaScript, which takes something from the URL or page and writes it into the document unsafely. The dangerous step happens entirely in the browser, without the server ever reflecting anything.

For your first bug hunts, reflected and stored are what you will meet most. The question to ask at every input is the XSS question: *does my text come back out inside the page, and does it come back as text or as runnable code?*

4 The fix: encode on output

The cure mirrors SQL injection's cure: keep the user's data in the "data" box and never let it reach the page as code. For HTML the tool is output encoding.

Encoding turns a script into harmless text
Encoding turns a script into harmless text

Encoding rewrites the handful of characters that have special meaning in HTML into harmless stand-ins the moment you put user data into a page:

<  becomes  &lt;
>  becomes  &gt;
"  becomes  &quot;
&  becomes  &amp;

Now <script>steal()</script> is written into the page as the literal, visible characters &lt;script&gt;... — the browser displays the text and runs nothing. The payload became inert the instant it was encoded for its destination. This is exactly what this platform's own lesson renderer does with every piece of text, which is why typing a script into this very box would simply show the script, not run it.

The key subtlety: you encode for the destination. Encoding for HTML is different from encoding for a JavaScript context or a URL. Put data in the wrong place even with the wrong encoding and you can still have a bug — but for the common case of "user text displayed in a page," HTML output encoding is the answer, and any decent template engine does it automatically.

5 Safety nets

Encoding is the primary fix. On top of it, professionals add layers so that a single missed spot is not catastrophe — the same defence-in-depth idea you will see throughout security.

  • HttpOnly cookies. Mark the session cookie HttpOnly and JavaScript is forbidden from reading it. Now even if an XSS does fire, document.cookie cannot hand the session to the attacker — you have taken away the usual prize. The cookie flag that blocks JavaScript access is literally named HttpOnly.
  • Content-Security-Policy (CSP). A CSP response header tells the browser which scripts are allowed to run. A good policy refuses to run inline injected scripts at all, so even a successful injection does nothing.
  • Input validation. Reject obviously malformed input early. This is not the main defence for XSS — encoding is — but it trims the attack surface.

Stack HttpOnly and a CSP on top of correct output encoding and XSS goes from "easy win" to "very hard to pull off."

Tip Encode output to stop the script running; set HttpOnly so that if one slips through, it still cannot steal the session cookie. Primary fix plus safety net.

Submit the keys below when you can explain the whole story.

Submit your keys

Keys are not case-sensitive. Each is worth points the first time you get it right.

Key 1What does a successful XSS attack usually try to steal, because possessing it lets the attacker become the logged-in victim? (Two words.)

+25 pts

Show a hintIt is the wristband the server gave the user at login. ("cookie" alone is accepted.)

A written solution is included with Pro, or appears here once you solve it.

Key 2What is the primary defence against XSS — the technique that turns characters like < and > into harmless text when user data is placed into a page? (Two words.)

+25 pts

Show a hintYou do it on the way out, for the destination (HTML). ("encoding" alone is accepted.)

A written solution is included with Pro, or appears here once you solve it.

References

Next exerciseCommand Injection →