The Exploit HQ

Explained Live · lesson 3 · 2026-09-04 · updated 2026-10-12

XSS Explained — See a Website Get Hijacked Live

Before you start

Cross-site scripting is one of the oldest vulnerabilities on the web — and once you see it happen, you will never trust a search box or a URL parameter the same way again. In this video, we run a live cross-site scripting attack against a practice app, inject a script that runs inside the victim’s browser, and walk through how that script steals a session cookie and what it takes to stop it. Here we go.

Let’s start with the concept.

What is cross-site scripting?

Every time a website reflects something back at you — a search term, a name, a query parameter — it is building an HTML page with your input inside it. If the server drops your input straight into the page without cleaning it first, and you sent a script tag instead of plain text, the browser has no way to know it was not supposed to be there. It runs the script. That script has access to everything the page has access to — including the session cookie that keeps you logged in.

Here is what that looks like in practice.

Step 1 — a normal reflected input

curl -s -b lab/cookies.txt "http://127.0.0.1:8080/vulnerabilities/xss_r/?name=Alice&Submit=Submit" | grep -oP "Hello \w+"
Part What it does
?name=Alice the value the app puts directly into the HTML response
grep -oP "Hello \w+" pull just the reflected text from the page

Hello Alice — exactly what we sent, reflected back. The server took the name parameter and put it directly into the page. That is the normal behavior. Now watch what happens when we send something other than a name.

Instead of a name, we send a script tag. The opening tag, a JavaScript alert call, and the closing tag. No special encoding — just plain text that looks like code.

Step 2 — inject a script tag

curl -s -b lab/cookies.txt "http://127.0.0.1:8080/vulnerabilities/xss_r/?name=%3Cscript%3Ealert(1)%3C%2Fscript%3E&Submit=Submit" | grep -oP "<script>[^<]+</script>"
Part What it does
%3Cscript%3E URL-encoded < and > — the browser decodes these back to a script tag
alert(1) the JavaScript payload — any code goes here
grep -oP "<script>..." find the script tag in the server’s HTML response

The script tag is in the server’s response — unsanitized, exactly as we sent it. A real browser loading this page would execute that JavaScript immediately. The alert fires. And alert is the harmless proof-of-concept. The real payload is the one that steals the session cookie.

Before we run the cookie-stealing payload, let us understand what it does in a real attack.

What a real payload does

The payload is document.write of document.cookie. Document.cookie is a built-in JavaScript property — every page has it, and it holds every cookie the site has set for this domain, including the session token that keeps you logged in. Document.write puts that value directly into the page. We wrap it in a script tag, URL-encode the angle brackets the same way we did in step two, and the server reflects the whole thing back. In a real browser, the script runs the moment the page loads and the cookie appears in plain text — ready to be sent to an attacker’s server with one fetch call.

curl -s -b lab/cookies.txt "http://127.0.0.1:8080/vulnerabilities/xss_r/?name=%3Cscript%3Edocument.write%28document.cookie%29%3C%2Fscript%3E&Submit=Submit" | grep -oP "Hello <script>[^<]+</script>"
Part What it does
document.write(document.cookie) the payload — writes the raw cookie string into the page
%3Cscript%3E ... %3C%2Fscript%3E URL-encoded script tags — the browser decodes them back
grep -oP "Hello <script>..." pull the full reflected line from the server’s HTML response

The server embedded that script alongside the greeting. In a browser, document.write runs immediately and prints the raw cookie string to the page — including the session token. An attacker using a fetch payload instead of document.write would silently POST that cookie to a server they control. One crafted URL. One click from a logged-in victim. Session stolen.

How do you find this, and how do you fix it?

Find it. Fix it.

The fix has three layers and you want all three. Output encoding is the primary defense — every character that could be interpreted as HTML gets converted to its safe equivalent before the server writes it to the page. The browser then displays it as text instead of running it. Content Security Policy adds a second layer: even if encoding is missed somewhere, a strict C.S.P. header prevents inline scripts from executing. And the HttpOnly flag on your session cookie means that even a successful injection cannot read it — the browser refuses to expose HttpOnly cookies to JavaScript. Layer all three. Encoding alone has blind spots.

One rule, every time.

Before you go

Only ever test applications you own or have explicit written permission to test. Sending a script tag to a site you do not own is still an unauthorized test, even if the payload is just alert of one. DVWA is built for exactly this kind of safe, legal practice — it runs entirely on your local machine. O-WASP lists cross-site scripting under A-03 Injection in their top ten web application risks. If you want to go deeper, the full Web Application Security beginner series is linked in the description — Parts one through four cover access control, file inclusion, information disclosure, and parameter tampering. Thanks for watching, and I will see you in the next one.