- name
- hunt-xss
- description
- Hunting skill for Cross-Site Scripting (XSS) — DOM-based, stored, reflected, mutation-based (mXSS), and modern variants.
- sources
- hackerone_public, github_advisories, github_deep, intigriti, huntr, bugcrowd, project_zero, microsoft_msrc, securitylab_github, nvd_verified, cure53_advisories, portswigger_research
- report_count
- 1500
- generated_at
- 2026-05-04T00:00:00.000Z
## Crown Jewel Targets
XSS is the highest-frequency web bug class but the modern paying surface has shifted. Reflected XSS on a public marketing page is mid four-figure at best; stored XSS chained to admin ATO is mid five-figure; mXSS bypass of a popular sanitizer pays direct from Cure53/Snyk plus downstream chains. The 24-month meta has crystallized around six asset types. All CVEs below are NVD-verified.
**1. DOMPurify mXSS bypass family (high four-figure to mid five-figure direct + thousands of downstream chains).** Every DOMPurify bypass disclosed since 2024 has cascaded through every consumer that hadn't pinned to the latest version. **CVE-2024-47875 (GHSA-gx9m-whjm-85jf, Oct 2024, GitHub CVSS 10.0)** — nesting-based mXSS by @IcesFont via cure53berlin disclosure. Versions <2.5.0 and <3.1.3 vulnerable. **CVE-2024-45801 (GHSA-mmhx-hmjr-r674)** — companion depth-bypass weakened by prototype pollution; backport reference. **GHSA-h8r8-wccr-v5f2 — DOMPurify mXSS via Re-Contextualization in 3.3.1** (Oscar Uribe / Camilo Vera / Cristian Vargas, Fluid Attacks Research) — sanitized output reinserted via `innerHTML` into a wrapper (`script`, `xmp`, `iframe`, `noembed`, `noframes`, `noscript`) mutates during second parse. **Yaniv Nizry @YNizry Dec 2024** — DOMPurify 3.2.1 non-default-config bypass via `is` attribute mishandling. **@kinugawamasato deep-nesting variant** — works on Firefox + Chromium + Safari (most other mXSS techniques only work on one browser). **@hash_kitten HTML insertion modes bypass** — full bypass without nesting. **@ryotkak XML-based bypass**. The mizu.re writeup at https://mizu.re/post/exploring-the-dompurify-library-bypasses-and-fixes is the canonical recent reference. Hunt every DOMPurify consumer that hasn't pinned to current; pays per-target.
**2. Modern JS / RSC / Server Actions content rendering (low to mid five-figure).** Next.js Server Components and Server Functions deserialize and render client-supplied content. The DoS family (CVE-2025-67779, CVE-2025-55184, GHSA-5j59-xgg2-r9c4 published Dec 11, 2025) demonstrates that the RSC runtime trusts payload structure; the same trust surface produces XSS when RSC payloads or Server Action responses round-trip through `dangerouslySetInnerHTML` or React's HTML escape boundary. Affects React 19.0.0/19.1.0/19.1.1/19.2.0 with `react-server-dom-webpack` / `parcel` / `turbopack`; patches in React 19.0.2/19.1.3/19.2.2 and Next.js 14.2.35 / 15.x point releases / 16.0.10. The Vercel Platform Protection WAF program pays for new bypass primitives.
**3. OAuth `redirect_uri` / `returnTo` XSS (low five-figure on enterprise SaaS).** **CVE-2025-67716 (GHSA-mr6f-h57v-rpj5, Dec 10 2025)** — Auth0 Next.js SDK <4.13.0 — `returnTo` parameter input-validation flaw lets attackers inject unintended OAuth query parameters into the authorization request. Disclosed by Joshua Rogers / @MegaManSec via Okta. The pattern: any OAuth library that takes `redirect_uri` / `returnTo` / `state` / `RelayState` (SAML) and reflects it back into HTML (error page, success page, logout page) without proper escaping. The HackerOne TopOAuth list (reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPOAUTH.md) has dozens of disclosed cases — Reflected XSS at oauth2/fallbacks/error against Zomato/ORY Hydra, XSS at OAuth authorize/authenticate against X/xAI, XSS in OAuth Redirect Url at Dropbox, Stored XSS in OAuth redirect URI at Nextcloud, OAuth redirect_uri bypass via IDN homograph at Semrush (bounty $0 as the program disclosed it informational — but the technique generalizes; HackerOne disclosed write-up).
**4. postMessage XSS with origin-check bypass (mid four-figure to low five-figure on banking / fintech / chat-widget integrations).** Almost every postMessage implementation has at least one of these problems: no origin check, broken origin check (`includes()` instead of `===`), trusts message data without sanitization. **CleverTap Web SDK <=1.15.2 issue #424 (Mr-Neutr0n, Jun 2025)** — `event.origin` checked with `.includes()` allowing bypass via `dashboard.clevertap.com.attacker.com`; `display.details[0].html` field assigned to `element.innerHTML` without filtering. Bug Bounty Playbook documents this as the dominant chat-widget integration pattern: vendor's domain has its own XSS, attacker uses it to send crafted messages that pass the bank's origin check, executing in banking session context. Hunt every `addEventListener('message', ...)` in every JS bundle.
**5. Stored XSS → Admin Account Takeover via shared-content features (mid four-figure to mid five-figure).** **GHSA-jmr4-p576-v565 (listmonk, Jan 2 2026, CVSS 8.0)** — campaign-management user injects XSS payload into newsletter draft, super-admin reviews → backdoor admin created. Weaponized via public archive feature — victim simply visits link, no preview click required. Pattern repeats across CMS, mailers, ticketing systems, support tools where lower-privileged content reaches higher-privileged viewers. **Apple Discussions Stored XSS** — $5,000 bounty disclosed via Apple Security Bounty program May-Jul 2025, ZombieHack writeup at https://medium.com/@ZombieHack/apple-developer-stored-xss-5-000-bounty-writeup-2025-cc34a030a5bf — discussions.apple.com initial XSS, partial fix bypassed, re-enabled across mirrors and developer.apple.com/forums; Apple acknowledged, broader fix.
**6. Markdown / wiki / comment renderer XSS.** **CVE-2024-21535 (markdown-to-jsx <7.4.0)** — `src` property iframe injection. Markdown renderers and their plugin ecosystems are systematically under-audited because devs trust the "markdown sanitizes HTML" assumption. Reference: gregxsunday's "$3,133.70 XSS in golang's net/html library" — disclosed via Google bug bounty program for finding XSS in the parser the renderer depends on, not the renderer itself. Hunt every wiki/comment/issue-tracker/chat that supports markdown formatting.
**7. Rich-text editor XSS — Trix family (mid four-figure to low five-figure).** Trix is the rich-text editor shipped by Basecamp / 37signals and embedded across many SaaS (Basecamp itself, HEY, plus many ActionText-using Rails apps). **Trix Editor 2.1.8 Mutation-Based Stored XSS** — H1 report 2819573 (2025 Critical). **Trix Editor 2.1.1 Stored XSS** — H1 report 2521419 (2024 High). Pattern: rich-text editors store HTML structure including attachment/embed metadata; sanitizer-vs-renderer mismatch produces mXSS on render. Same class hits CKEditor, TinyMCE, Quill, Slate, Lexical when consumers don't pin to current versions. Hunt every rich-text editor instance for: attachment-tag injection, embed-figure manipulation, paste-from-Word residue, drag-and-drop HTML smuggling.
**8. Jupyter / data-science notebook XSS (mid four-figure to low five-figure on data-science platforms).** **GHSA-rch3-82jr-f9w9 (Jupyter Notebook 7.0.0-7.5.5 / JupyterLab through 4.5.6, CVSS 8.4 High)** — CommandLinker XSS in malicious notebook files steals authentication tokens enabling REST API ATO. **H1 report 1409788 (2022) — Arbitrary POST request as victim user from HTML injection in Jupyter notebooks**. Notebook file (`.ipynb`) is JSON with cells containing user-controlled markdown/HTML rendered by the Jupyter frontend. Hunt: Jupyter Hub instances, Google Colab-style platforms, Hex / Deepnote / Databricks notebooks, ML platforms with notebook UI, any "share this notebook" feature.
**9. n8n / workflow-automation MCP OAuth XSS (intersects hunt-llm-ai).** **GHSA-537j-gqpc-p7fq (n8n <1.123.32 / <2.17.4 / <2.18.1, CVSS 8.8 High)** — unauthenticated XSS via crafted `client_name` in MCP OAuth client registration; executes JavaScript in admin authorization dialog. Pattern repeats across automation platforms exposing MCP / OAuth client registration endpoints (Zapier, Make, Pipedream when MCP-enabled). Cross-reference: hunt-llm-ai.md Crown Jewel #7 covers the broader MCP server attack surface.
**Government & enterprise legacy assets (DoD VDP through low five-figure on paid programs).** Old PHP/JSP/ASP apps with `<?php echo $_GET['x']; ?>` patterns still pay on intranets. The 2024-2026 H1 hacktivity is full of "Stored XSS in admin notes leading to ATO" against forgotten asset surfaces. Confluence, JIRA, SharePoint older versions all in rotation.
**LinkedIn-class consumer-social platforms.** **H1 report 2212950 (2024 Critical) — Stored XSS on LinkedIn App via iframe tag in Article**. Article-publishing features on consumer-social platforms accept rich content; iframe smuggling through "embed" features bypasses sanitization. Pattern: any UGC platform with article/post-publishing features (LinkedIn Articles, Medium, Substack, Dev.to) is a candidate.
**Mobile WebView XSS** — apps that load partially-attacker-controlled URLs in WebView with `addJavascriptInterface` enabled escalate XSS to RCE. Documented across H1 mobile-target hacktivity disclosed 2024-2025 against Shopify, GitLab, Vercel mobile programs.
**What pays the most:** mXSS bypass of a popular sanitizer (DOMPurify / sanitize-html / bleach class) — direct from Cure53/Snyk + downstream chains, total mid five-figure across consumers. Stored XSS chained to admin ATO via shared-content trigger — mid four-figure to mid five-figure. OAuth redirect_uri XSS chained to token theft — low five-figure on enterprise SaaS. postMessage XSS chained through trusted-widget vendor to banking session — mid five-figure on financial programs. Reflected XSS without chain pays low four-figure or N/A on most modern programs.
## Attack Surface Signals
Greppable signals that this surface might exist:
```bash
# DOMPurify usage with version pin (look for outdated)
rg -n 'dompurify' --type js --type ts -g 'package*.json'
rg -n 'DOMPurify\.sanitize\(' --type js --type ts
# Dangerous sinks (innerHTML, outerHTML, document.write, eval)
rg -n -e 'innerHTML\s*=' -e 'outerHTML\s*=' -e 'document\.write\(' \
-e 'eval\(' -e 'setTimeout\([^,]*[\'"]' -e 'Function\(' \
--type js --type ts
# postMessage handlers — check origin validation
rg -n -B 2 -A 15 'addEventListener\([\x27\x22]message[\x27\x22]' \
--type js --type ts | rg -v 'event\.origin\s*===|origin\s*===|\.origin\.endsWith'
# React dangerouslySetInnerHTML — every usage is a candidate
rg -n 'dangerouslySetInnerHTML' --type js --type ts --type jsx --type tsx
# Markdown renderers (marked, markdown-it, markdown-to-jsx, remark)
rg -n -e 'require\([\x27\x22]marked[\x27\x22]\)' \
-e 'from [\x27\x22]marked[\x27\x22]' \
-e 'markdown-it' -e 'markdown-to-jsx' -e 'remark-html' \
--type js --type ts -g 'package*.json'
# Trusted Types policy creation — check for unsafe transforms
rg -n 'trustedTypes\.createPolicy' --type js --type ts
# Server-side render with untrusted HTML (Next.js, Nuxt)
rg -n 'dangerouslySetInnerHTML|v-html\s*=' --type js --type ts --type vue
# Prototype pollution gadgets that produce XSS
rg -n -e '_\.merge\(' -e '_\.mergeWith\(' -e 'Object\.assign\(\{\},' \
-e '\$\.extend\(true,' --type js --type ts
# OAuth redirect_uri / returnTo / RelayState reflection
rg -n -i 'redirect_uri|return_to|returnto|relaystate' --type js --type ts --type py --type java --type go
```
HTTP-level signals on a live target:
- `<script src="...dompurify@2.x.../">` or `<script src="...purify@3.0..."` in HTML head or response body — **DOMPurify version probe**, check against current to identify CVE-2024-47875 / CVE-2024-45801 candidates
- React/Next.js fingerprint (`__NEXT_DATA__`, `_next/static/`, `Server-Action:` header) on response → **CVE-2025-67779 family RSC content trust surface**
- Auth0 `<script src="https://cdn.auth0.com/js/auth0/...">` or `@auth0/nextjs-auth0` in package.json — **CVE-2025-67716 returnTo candidate**
- OAuth `redirect_uri=https://target/callback?error=...` reflected back in error page — **OAuth XSS surface**
- `Server: nginx/1.x` + `X-Powered-By: Express` + `addEventListener('message'` in any `.js` — **postMessage XSS candidate**
- Embedded chat widget URLs (`crisp.chat`, `intercom.io`, `clevertap.com`, `drift.com`) — **vendor postMessage origin-check bypass** (CleverTap-style `.includes()` issue #424)
- Markdown rendering features (issue trackers, wikis, comments, support forms) — **markdown-to-jsx / marked / markdown-it XSS** (CVE-2024-21535 family)
- `Content-Security-Policy:` header missing or with `script-src 'unsafe-inline'` or `script-src https://cdn.attacker-controlled.com` — **CSP bypass surface**
- `Content-Security-Policy:` with `require-trusted-types-for 'script'` — **Trusted Types target** (look for policies that pass through user input)
- SVG file upload + serve from same origin — **SVG XSS surface** (`<svg onload=alert(1)>`)
- listmonk / Mautic / Mailchimp-clone in admin pages — **GHSA-jmr4-p576-v565 family** (campaign template XSS → super-admin trigger)
- Apple Discussions / forum software with public-archive feature — **stored XSS via shared content** (Apple Security Bounty pattern)
- Confluence `<5.x`, JIRA legacy, SharePoint older versions on intranets — **CVE replay XSS surface**
## Insertion Point Taxonomy
Every place attacker-controlled HTML/JS flows for XSS:
- **URL path / query / fragment** — `?q=<script>alert(1)</script>`, `#name=<svg onload>`, fragment-only XSS for CSP-mediated reflection. Test path segments — `/page/<script>` if path is reflected.
- **Headers** — `User-Agent`, `Referer`, `X-Forwarded-For` reflected in error pages, admin logs, debug pages. Server header reflection for SSI / template engines. `Origin:` reflected in CORS preflight error pages.
- **Body** — JSON values rendered as HTML (`{"message": "<script>"}`), form fields reflected on confirmation page, file content rendered (CSV columns rendered as HTML, JSON values as text).
- **Cookies** — `document.cookie` rendered in admin debug page, cookie value reflected in 500 page, session-cookie value in JWT claim shown as user info. Grammarly stored-XSS-via-cookie disclosed 2024-2025 (Bug Bytes #48 reference, $2,000 H1).
- **File contents** — uploaded SVG (`<svg onload>`), uploaded HTML attachment (gmail-style), CSV exported then rendered, EXIF metadata displayed in image viewer, font names rendered in admin UI.
- **postMessage data** — `event.data.html` assigned to `innerHTML` (CleverTap pattern); `event.data.url` assigned to `location.href` (DOM-based open redirect → XSS via `javascript:`); origin check via `includes()` bypassable.
- **OAuth `redirect_uri` / `returnTo` / `state` / `RelayState`** — reflected in error page, success page, logout page. CVE-2025-67716 Auth0 SDK is the canonical 2025 case.
- **WebSocket frames** — JSON message rendered as HTML in chat UI, often missed by HTTP-only WAF.
- **Background/async paths** — email confirmation links rendering attacker-controlled text, scheduled-report rendering CSV rows as HTML, notification-center rendering crafted notification content.
- **Indirect (stored)** — DB-stored content rendered later via `innerHTML`, file uploaded then rendered (filename in admin file-list), git commit messages echoed by CI (CI build-status pages), markdown READMEs rendered in package-detail pages.
- **CSS injection sinks** — `<link rel=stylesheet href="data:text/css,...">`, `style="..."` attribute injection, CSS expressions in older IE/Edge legacy contexts.
- **Markdown / wiki / comment renderers** — `[link](javascript:alert(1))`, `[link](data:text/html,...)`, `<img src=x onerror=alert(1)>` smuggled through markdown's HTML passthrough, `<script>` in fenced code blocks rendered without `noscript` wrapping.
- **Server Components / Server Actions** — RSC Flight payloads, Server Action response bodies that round-trip through `dangerouslySetInnerHTML`, hydration mismatch produces XSS.
- **LLM output rendering** — agentic AI output pasted directly into `innerHTML` without sanitization (chatbot UI, code-suggestion UI). Prompt-inject the LLM to emit `<img src=x onerror=...>`.
For each surface, send: `<script>alert(1)</script>`, `<svg onload=alert(1)>`, `<img src=x onerror=alert(1)>`, `"><script>`, `'><script>`, `javascript:alert(1)` (for href/src sinks), `data:text/html,<script>alert(1)</script>` (for src sinks). Watch for executed alert OR Burp Collaborator hit OR DOM mutation.
## Step-by-Step Hunting Methodology
1. **Fingerprint the JavaScript stack first.** Identify React/Vue/Angular/vanilla, sanitizer in use (DOMPurify? sanitize-html? bleach?), framework version, CSP header. Without stack knowledge you'll waste payloads on impossible vectors.
2. **Run DOM Invader (Burp built-in) on every authenticated page.** PortSwigger's DOM Invader automatically identifies sources, sinks, and prototype pollution vectors. It's faster than manual JS audit on first pass. Enable the prototype-pollution scanner specifically.
在 GitHub 查看