Skip to content
All modules
CoreModule 12 of 2790 minutes

Client-side: XSS and the browser's trust model

Get your JavaScript to run in someone else's page, past a CSP and an admin bot - and see why polluting a prototype changes every object in the process.

Assumes10. Web recon and attack surface

By the end you can

  • Distinguish reflected, stored and DOM-based XSS by where the sink is, not where the payload went in
  • Read a Content-Security-Policy and name what it forbids, what it permits, and the gadget that gets past it
  • Exfiltrate a cookie or a bot's session to a collector you control
  • Recognise a prototype pollution sink and chain it to a gadget already in the page
  • Explain the same-origin policy in terms of what it protects, and name three legitimate exceptions to it

1. Read

2. Use the tools

In the order they come up while solving. Read what each one does, or go straight to the workspace tab that runs it.

3. Try one now

Generated in your browser and checked in your browser. No account, nothing to download, and a fresh one whenever you want another.

4. Practise on the real thing

Real picoCTF challenges that use these techniques, easiest first. 29 match in total - see the full index.

Common mistakes

The wrong turns this topic reliably produces. Written as the mistake rather than the rule, because the rule is easy to agree with and easy to walk straight past.

  • Testing with alert(1) against an admin bot that has no alert handler. The proof of execution has to be something you can observe, which usually means a request to a collector.
  • Reading encoded output as safe. Encoding is context-sensitive: HTML-escaping inside a script block or a URL attribute protects nothing.
  • Chasing the injection point in DOM XSS. The bug is in the sink - innerHTML, document.write, a template compiler - and the source may be untouched.
  • Reusing one payload across contexts. An attribute, a template literal, a JSON blob and an existing script block each need a different break-out, and the payload that fires in one of them is inert in the other three.
  • Reading a CSP as a wall rather than as an allowlist. A permitted CDN carrying a JSONP endpoint or an old framework build is a script source under your control, so the directive worth studying is what it admits, not what it blocks.

Checkpoint

Land a payload that makes the challenge's bot issue a request to a URL you control, carrying its session, and state which CSP directive you had to work around.

Teaching note

The admin bot confuses people more than the payload does. Draw the flow once - your payload is stored, a headless browser with the flag cookie visits, your JavaScript runs as that browser - and most of the class stops trying to exfiltrate their own cookie.

Go deeper

The lessons above are written to get you through a challenge. These are the chapters to read when you want the subject instead - each one named so you can check it rather than take our word for it. Nothing here is affiliate-linked or sold by us.

  • Bug Bounty Bootcamp - Vickie Li

    Chapter 6, Cross-Site Scripting

    Sorts XSS by sink and context, which is the taxonomy that actually predicts which payload works.

  • Bug Bounty Bootcamp - Vickie Li

    Chapter 19, Same-Origin Policy Vulnerabilities

    The rule the whole module depends on, plus the exceptions attackers live in.

  • Real-World Bug Hunting - Peter Yaworski

    Chapter 7, Cross-Site Scripting

    Disclosed reports where the interesting part is where the payload landed, not what it was.

  • Hunting Security Bugs - Tom Gallagher, Bryan Jeffries, and Lawrence Landauer

    Chapter 10, HTML Scripting Attacks

    Predates most modern defences, which makes the underlying parsing problem unusually visible.