Get Started

Stop XSS and clickjacking with security headers and a CSP

This is the defend side of web security, the companion to the Burp lesson where you attacked a web app. Here you run a tiny web page on your own machine that has one deliberate hole: it reflects whatever a visitor types straight back into the HTML without escaping it. You watch an injected script run and change the page, then you add the HTTP security headers every site should send, write a Content Security Policy that blocks the injection while still allowing your own scripts, and roll it out safely with Report-Only so you never break your own site. The proof is the before and after, captured for real: the headers absent then present, the injected script running then refused, and the browser's own Content Security Policy violation message. Everything runs against a demo page you build and own, on 127.0.0.1, and nowhere else.

52 minIntermediateTools: FreeStep 1 free
Tested 12 Oct 2026 · Node.js 26.7.0 (the demo server uses only Node's built-in http and crypto, zero packages to install) and curl 8.17.0 on Windows 11. The before/after page behaviour and the browser console violations were captured with Playwright 1.49.1 driving its bundled Chromium against the kit's demo-server.js on 127.0.0.1:4280. Every curl header block, every console message and both page screenshots below are from that run. The nonce values shown are real but random per request, so yours will differ. The same server runs unchanged on macOS or Linux (and in WSL2 on Windows); only the command to set the MODE variable changes, which each step shows.
A tiny demo page on your own machine with one real reflected-XSS hole, so you have something lawful to break and then fix, plus the kit demo server, a headers snippet and an annotated CSP example to keep
A real before-and-afterthe security headers missing then present in curl, and the injected script changing the page then being refused, with the browser's own Content Security Policy violation message as proof
A CSP you understand line by line (default-src, script-src, 'self', nonce, frame-ancestors), and the safe way to roll one out with Report-Only so it never takes your own site down
Before you start
  • Node.js installed (to run the demo server) and curl (built into Windows 10/11, macOS and Linux). If Node is new to you, the Level 0 lesson Install anything from GitHub covers getting tools onto your machine first
  • Any modern browser with its developer console (the F12 panel), to see the page change and read the Content Security Policy violation. Chrome, Edge or Firefox are all fine
  • The companion lesson Web app pentesting with Burp Suite is a good pairing: there you exploit XSS and broken access control, here you shut them. It is not required, but the two sides reinforce each other
  • No GPU, no cloud account and nothing to buy. The whole lesson runs on 127.0.0.1 on your own computer
01/07Why headers, and what XSS and clickjacking are0 done
STEP 01 of 07~6 min

Why headers, and what XSS and clickjacking are

Understand the two attacks you are about to stop, and fix in your mind that this only ever runs against your own page.

  1. When a browser asks your server for a page, the reply comes in two parts: the page itself, and a set of headers, which are labelled notes at the top of the response that tell the browser how to treat what follows. Most headers are routine (how long to cache, what type the content is). A handful of them are security instructions: they tell the browser to refuse things that would otherwise be allowed. Sending those few headers is one of the cheapest, highest-value things you can do for a site, because the browser does the enforcing for you on every visitor's machine.

  2. The first attack they defend against is cross-site scripting, almost always written XSS: a flaw where text a visitor supplies ends up running as code in someone's browser, because the app dropped that text into the page without neutralising it. It comes in three shapes, one line each. Reflected XSS bounces straight back off a single request (a search term echoed into the results page), and is what this mission uses. Stored XSS is saved on the server first (a malicious comment) and then served to everyone who views it. DOM XSS never touches the server at all; the page's own JavaScript writes attacker-controlled text into the document. All three end the same way: code the site's owner never wrote, running with the full trust of the site.

  3. The second attack is clickjacking: an attacker loads your real site inside an invisible frame on their own page, lines up a button under the visitor's cursor, and tricks them into clicking something on your site they never meant to click (confirm a payment, change a setting). The defence is to tell browsers that your pages may not be put inside anyone else's frame.

  4. You stop both with headers, and the strongest of them is a Content Security Policy (CSP): a single header that lists exactly what a page is allowed to load and run, so the browser refuses everything else, including an injected script. The rest of the lesson builds one up and proves it works.

    CarefulEverything here runs against a demo page you build and serve yourself, on 127.0.0.1, your own machine. That is what makes it lawful. The same curiosity pointed at a website you do not own is a different thing entirely: probing or injecting into someone else's site without written permission is a criminal offence in the UK (the Computer Misuse Act 1990) and in most other countries, even if nothing breaks. Test on your own site only.
    TipA useful way to hold the whole lesson in your head: an injected script and your own script look identical to the browser once they are on the page. The browser cannot tell attacker from author by reading the code. A CSP gives it a way to tell them apart, by demanding proof (a secret token, or an exact match) that a script is one you meant to allow.
✓
CheckpointYou can say in one sentence what XSS is and what clickjacking is, and why a header the server sends can stop an attack that happens in the visitor's browser.
Stuck? Ask the community
Next mission · Ethical hackingTest your own API for the flaws attackers look for
→