Skip to content

What is cross-site scripting (XSS)?

A browser can't tell a stranger's words from the site's own code unless the site marks them as text.

Choose which version to show
guestbook.lab
Alex typed
<b>hello</b>

Alex wrote: hello

Alex wrote: <b>hello</b>

Made up, and harmless. A bold tag doesn't run anything.

All six guides
  1. 1What is ethical hacking?
  2. 2Where to practice
  3. 3Business logic bugs
  4. 4IDOR
  5. 5Cross-site scripting
  6. 6A report, with notes

Cross-site scripting, or XSS, happens when a site takes something a user typed and puts it into a page in a way that lets the browser read it as instructions instead of words. If those instructions include JavaScript, it can run in the browser of whoever opens that page.

The examples below use a made-up guestbook. Typing a tag into a real site's comment box is testing that site, even if it's only bold, and other people may see it. Get permission before you access anything, stay in the practice labs, and never touch a real site. The ethics agreement is how BugClub HQ holds students to that.

A browser can't tell who wrote what

A web page is a long run of text. Some of it is content, like a sentence you read. Some of it is HTML, which tells the browser how to build the page. Angle brackets mark the difference. When the browser reaches <b>, it doesn't show those three characters. It treats them as an instruction to make what follows bold.

A guestbook has to put what you typed into that same run of text. If it pastes your message straight in, the browser can't tell your words from the site's own HTML.

What a bold word shows you

A made-up visitor named Alex signs the made-up guestbook with this:

<b>hello</b>

A site that handles this properly shows it exactly as typed, brackets and all:

Alex wrote: <b>hello</b>

A site with the bug shows this:

Alex wrote: hello

The brackets are gone because the browser took them as an instruction. Nothing ran, because a bold tag only changes how a word looks. But a stranger's text got to give the browser instructions. In a practice lab, that's enough proof, and you stop there.

What actually runs, and where

HTML describes a page. JavaScript is a program, and browsers run programs. The hole that lets in a bold tag can let in JavaScript too, unless something else blocks it. Strictly speaking, a bold word on its own is called HTML injection. It's XSS when JavaScript can run.

That JavaScript runs in the viewer's browser. The server only stores and sends text. The browser treats it as the site's own code, so it can do what the site's own code can do for that person: read and change the page, and send requests to the site as them if they're signed in.

That's how the MySpace worm spread in October 2005. Samy Kamkar put a script in his own profile, and it copied itself onto the profile of anyone who viewed it. It reached over a million users in about 20 hours. He pleaded guilty in 2007.

Stored and reflected

The two common kinds differ in where the text lives and who it reaches.

Stored means the site saves it. A guestbook entry, a comment or a bio goes into the database, and the site puts it into the page for everyone who opens that page. Nobody has to do anything except visit. The MySpace worm was this kind.

Reflected means the site doesn't save it. A search page that repeats what you typed sends your words back for that one request. It reaches only the person whose request carried it, so anyone else would have to be tricked into opening a link.

There's a third kind, DOM-based, where the page's own JavaScript writes the text into the page in the browser after it loads. The cause is the same in all three: a user's text went into the page without being marked as text.

The fix is output encoding

Before a site puts a user's text into a page, it swaps the characters that mean something to the browser for codes that mean "just show this character." < becomes &lt; and > becomes &gt;. The browser draws the bracket on screen and never starts a tag, so Alex's message shows up exactly as typed. That's output encoding, and you'll also hear it called escaping.

It happens as the text goes into the page because the right encoding depends on where the text lands. A paragraph, an HTML attribute and a piece of JavaScript all follow different rules.

Most modern web frameworks do this for you by default. The bug tends to show up where a developer switches that off or builds the HTML by hand. If a site really wants people to post formatting, it needs a sanitizer, a tested library that keeps a short list of safe tags and removes the rest.

Filtering what people type doesn't replace encoding. Neither does a Content Security Policy, a rule that tells the browser which scripts it may run, though it's a useful backup if something slips through.

Week 4 of the curriculum covers this on a practice guestbook, and the proof stops at something harmless.

The course behind these guides

BugClub HQ is an eight-week online course in ethical hacking for anyone 14 and up. It runs in three groups, for high school students, college students and adults, and each one meets on its own night. You practice on apps with bugs put there on purpose, write up what you find, and get my feedback on every write-up. You don't need to know how to code.

Applications for the winter term close Dec 18

The winter term

$399 one time, only if accepted

Starts
January 11
Schedule
  • High school students: Thursdays, 5:30 to 7 PM Eastern
  • College students: Wednesdays, 6 to 7:30 PM Eastern
  • Adults: Tuesdays, 8:15 to 9:45 PM Eastern
Class size
Up to 12 per group
Apply for the winter term

Free to apply, about five minutes. You pay only if I accept the student.