Home
Cybersecurity & AI Security / Part 17 — Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS)

CAP, ACID vs BASE, latency numbers, back-of-envelope estimation, single points of failure — the vocabulary every system designer thinks in.


Core Philosophy: Cross-Site Scripting is injection again — but the injected code is JavaScript, and the place it runs is not the server but the browser of an innocent victim. XSS turns a trusted website into a delivery mechanism for the attacker’s code, executing with all the trust the victim’s browser places in that site. Because so much identity and power lives in the browser, XSS is one of the most impactful web vulnerabilities there is.

Part 1: The Problem

Web pages are built from HTML and JavaScript. When an application takes user input and places it into a page without properly handling it, an attacker can supply input that isn’t ordinary text but is JavaScript code. The browser, unable to tell the difference, executes it.

The crucial twist that makes XSS different from server-side injection: the code runs in the browser of whoever views that page — potentially thousands of innocent users. The website becomes the attacker’s accomplice, delivering malicious code under its own trusted name.

Part 2: The Concept — Injecting Into the Page

It’s the same data-vs-code confusion from 2.4, in a new context. An application takes user input and builds a web page with it:

text
   A page greets the user by name. It builds HTML:
   "<p>Welcome, "  +  INPUT  +  "</p>"

   NORMAL — input is data:
   Input: "Alice"
   Page becomes:  <p>Welcome, Alice</p>     ✓ harmless

   ATTACK — input is code:
   Input: "<script>alert('XSS')</script>"
   Page becomes:
   <p>Welcome, <script>alert('XSS')</script></p>
                └──────────────┬──────────────┘
              the browser EXECUTES this as JavaScript

The attacker’s input wasn’t displayed as text — it was injected into the page’s HTML, and the browser ran it as code. alert('XSS') is the harmless classic used to prove the vulnerability. Real attacker payloads do far more (Part 4).

Part 3: The Three Types of XSS

XSS is categorized by how the malicious script reaches the victim.

1. Reflected XSS — the script bounces off the server. The malicious script is part of a request (often in a URL parameter), and the server “reflects” it straight back in the response. The attacker must get the victim to click a crafted link.

text
   Attacker crafts a URL containing the script
        │
   Victim clicks it (phishing email, message, malicious page)
        │
   Server reflects the script into the response page
        │
   Script runs in the victim's browser

2. Stored XSS — the script is saved on the server. The malicious script is saved by the application — in a comment, a profile field, a forum post, a product review. Then it’s served to everyone who views that content. No clicking a special link needed; just viewing the page triggers it. This is the most dangerous type because it hits every visitor automatically.

text
   Attacker posts a comment containing the script
        │
   Server STORES it in the database
        │
   EVERY user who views that page receives the script
        │
   Script runs in every one of their browsers

3. DOM-based XSS — the injection happens entirely in the browser. The vulnerability is in the page’s own JavaScript, which takes attacker-influenced data and unsafely writes it into the page — the server may never even see the malicious part. It’s a client-side-only variant.

Type Where the payload lives Victim must…
ReflectedIn the request, reflected back immediatelyClick a crafted link
StoredSaved on the server, served to allJust view the page
DOM-basedHandled unsafely by the page’s own JavaScriptView / interact with the page

Part 4: Why XSS Is Dangerous — What an Attacker’s Script Can Do

“It just runs some JavaScript” sounds minor. It isn’t. JavaScript running in the victim’s browser, in the context of the trusted site, can do almost anything the user can — and more:

The severity comes from trust: the browser grants the script all the trust it grants the legitimate site. To the browser, the attacker’s injected script and the site’s real code are indistinguishable.

🔑 One important defensive concept worth knowing now: a cookie can be marked HttpOnly, which makes it unreadable by JavaScript. This single flag blocks the most direct cookie-stealing XSS payloads. It doesn’t fix XSS — the attacker can still act as the victim — but it’s a key piece of defense in depth you’ll apply in Phase 4.

Part 5: Finding XSS

The testing mindset mirrors 2.4 — find inputs, probe, observe — but here you’re watching whether your input lands in the page in a way the browser will execute.

text
1. FIND INPUTS    Every input that ends up DISPLAYED somewhere:
                     search boxes, comment fields, profile fields,
                     URL parameters reflected on the page, names,
                     messages — anything shown back to a user.
2. PROBE          Submit a harmless, unique marker, then a test
                     payload (the alert() classic). Use something
                     distinctive so you can find it in the page.
3. INSPECT        View the resulting page SOURCE. Did your input
                     appear as plain text (safe) or as live HTML/
                     script (vulnerable)?
4. CLASSIFY       Determine which type — reflected, stored, or
                     DOM-based — based on how it got there.
5. ASSESS         Confirm it executes. Then assess real impact
                     responsibly (see ethics note).
⚖️ Ethics of XSS testing. The alert() popup is the universal harmless proof — it demonstrates script execution without harming anyone. That is what you use to confirm and report XSS. Never test XSS with a payload that actually steals real users’ cookies or data, even on an in-scope bug bounty target — that harms real people and is a crime. Prove execution; do not weaponize it.

Part 6: A Glance at the Fix

XSS, like all injection, is fixed by correctly separating data from code. The defenses (built fully in Phase 4.1):

text
   VULNERABLE:  page = "<p>Welcome, " + input + "</p>"
                input "<script>...</script>"  → browser RUNS it

   SAFE (output encoding):  input is encoded before display
                "<script>" becomes harmless display text
                → browser SHOWS "<script>", never runs it

You’ll implement these in Phase 4.1 and then re-attack your own fix. The principle to carry forward: encode on output, treat all user input as untrusted, and let a good framework and CSP back you up.

📓 Key Terms

Term Plain meaning
XSS (Cross-Site Scripting)Injecting malicious script that runs in a victim’s browser.
Reflected XSSScript in a request, reflected back immediately; needs a crafted link.
Stored XSSScript saved on the server and served to all viewers.
DOM-based XSSXSS arising from the page’s own JavaScript handling input unsafely.
PayloadThe attacker’s malicious input/script.
Session hijackingTaking over a user’s session — a common goal of XSS.
Output encoding / escapingConverting input so the browser treats it as text, not code — the main fix.
Content Security Policy (CSP)Browser rules restricting which scripts may run — defense in depth.
HttpOnlyA cookie flag making the cookie unreadable by JavaScript.

🧪 Hands-On Lab

Only on your own lab or deliberately vulnerable practice apps. Use only harmless proof payloads like alert() — never real cookie/data-stealing payloads.

Task 1 — Reflected XSS. On a deliberately vulnerable app, find an input reflected in the response (a search box is classic). Inject the alert() payload. See the popup. View the page source and find your script in the HTML — confirm the browser treated it as code.

Task 2 — Stored XSS. Find a feature that saves your input and shows it later (a comment, a profile name, a guestbook). Store an alert() payload. Reload the page — the script runs. Now grasp the danger: it would run for every visitor, automatically.

Task 3 — DOM-based XSS. Find a DOM-XSS challenge. Use browser dev tools to trace how the page’s own JavaScript takes input and writes it unsafely into the page. Notice the server may never see the payload.

Task 4 — Read the source, every time. For each XSS you find, view the page source and locate exactly where and how your input landed. Building the habit of reading how input is reflected is what makes you good at finding XSS.

Task 5 — Understand the impact (conceptually). Read about what real XSS payloads do — cookie theft, acting as the user. Do not run such payloads. Understanding the impact is what lets you explain severity in a report; demonstrating it harmfully is off-limits.

Task 6 — See a defense work. Find an input in the app that is not vulnerable — where your payload appears as harmless text. View the source: your <script> shows up encoded. You’ve just seen output encoding (Part 6) doing its job. This previews Phase 4.1.

⚠️ Common Mistakes

✅ Recap & What’s Next

Next (2.6): We turn to the machinery from page 1.4 and attack it directly — broken authentication and session handling, the flaws that let an attacker simply become another user.

⁂ Back to all modules