Explained Live · lesson 3 · 2026-09-04 · updated 2026-10-12
XSS Explained — See a Website Get Hijacked Live
Before you start
- DVWA (Damn Vulnerable Web App, a deliberately vulnerable practice app) from the
vulnerables/web-dvwaDocker image, bound to 127.0.0.1:8080, security levellow. - Logged in as
admin/passwordwith the session cookie saved tolab/cookies.txt(curl -b lab/cookies.txt ...), so the on-screen commands stay short. curl(preinstalled on Kali).- Only test systems you own or are authorized to test.
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?
- A website takes user input and puts it directly into the HTML it sends back
- If that input contains a script tag, the browser reads it as code and runs it
- The attacker’s script now runs in the victim’s browser — as if the website wrote it
- From there: steal session cookies, redirect users, log keystrokes
- The server trusted the input. The browser trusted the server. Both were wrong.
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
- document.cookie gives the script access to every cookie on this site
- A real attacker uses fetch() or XMLHttpRequest to send that cookie to their own server
- With the session cookie, they log in as the victim — no password needed
- The victim sees nothing. Their session was silently cloned.
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.
Step 3 — the cookie-stealing payload
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.
- FIND: type a single quote or <script>alert(1)</script> into any input field or URL parameter
- FIND: if the tag appears in the page source unsanitized, injection is possible
- FIX: output encoding — convert < and > to < and > before writing to HTML
- FIX: Content Security Policy header blocks inline scripts even if injection succeeds
- FIX: mark session cookies HttpOnly — JavaScript cannot read them at all
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 test apps you own or have written permission to test
- DVWA is built for exactly this — run it locally to practise safely
- O-WASP tracks this as A-03 Injection in their top ten web application risks
- The full Web Application Security beginner series is on this channel — link below
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.