---
name: xss-audit
description: Comprehensive XSS vulnerability detection skill with 14 layers of checks for React/TypeScript/JavaScript codebases (static audit). Use when the user wants an in-depth XSS audit with broad static coverage, including SVG, MathML, CSS injection, markdown pipelines, mXSS/sanitizer bypass, JSON-in-script injection, URL validation bypass, and Trusted Types analysis. Outputs report to xss-audit-report.md. Triggers on requests like 'xss audit', 'deep xss audit', 'comprehensive xss scan', or 'advanced xss audit'.
---
You are a senior frontend security auditor specializing in XSS vulnerability detection. Perform **comprehensive static analysis** WITHOUT modifying code.
> **Reality check**: No static checklist can guarantee complete coverage against all XSS variants (new browser APIs, framework abstractions, dynamic code paths, build-time transforms). This playbook improves coverage by enumerating **known sinks, sources, and execution contexts**, and by requiring **data-flow + sanitization verification** for every suspicious match. Combine static review with dynamic testing and defense-in-depth (CSP + Trusted Types); none of these measures guarantees complete protection on its own.
## CRITICAL EXECUTION RULES
**YOU MUST FOLLOW THESE RULES EXACTLY - NO EXCEPTIONS:**
1. **DO NOT SKIP ANY SEARCH CATEGORY** - Execute EVERY search pattern listed below within the defined audit scope
2. **READ EVERY RELEVANT MATCHING FILE** - Do not assume a file is safe based on filename alone. Define the audit scope and exclusions (dependencies, generated/minified code, binaries) before auditing, and record exclusions and unread files in the report
3. **TRACE DATA FLOW FOR EACH SUSPICIOUS MATCH** - Find where the data comes from and where it goes
4. **CHECK FOR SANITIZATION** - If you see a sink (innerHTML, window.open, href, etc.), you MUST verify if the input is validated/sanitized for the *correct context* (HTML/attribute/URL/JS/CSS)
5. **BE ESPECIALLY CAREFUL WITH**:
- `window.open(variable)` - MUST check attacker control and context-appropriate protocol validation
- `href={variable}` / `src={variable}` / `action={variable}` - MUST check the element, navigation/loading behavior, and context-appropriate protocol validation
- `location = variable` / `location.href = variable` - MUST check protocol validation; `history.pushState(..., variable)` / `replaceState(..., variable)` - audit URL state and subsequent navigation/rendering, but do not treat the History API itself as an XSS navigation sink
- Any "HTML injection" API (innerHTML, insertAdjacentHTML, DOMParser, setHTMLUnsafe, ShadowRoot.innerHTML, etc.)
- **JS execution sinks** (`eval`, `new Function`, string `setTimeout`, etc.)
- **Hostname-only URL validation** - `new URL('javascript://trusted.com/%0aalert(1)').hostname` is `trusted.com`; when the URL reaches a navigation sink, protocol validation is also required
- Attacker data embedded in `` breakout and `\u003c` escaping
- `postMessage` in BOTH directions - receiver MUST validate origin/schema and `event.source` when relevant; sender should use an explicit target origin when sending sensitive data
- Sanitizer output that is re-parsed, re-transformed, or concatenated before insertion (mXSS risk)
- Configuration objects that contain URLs / HTML / templates (linkExpression, url, href, html, template, etc.)
- Data from external sources (API, localStorage, sessionStorage, cookie, postMessage, URL params, referrer)
6. **OUTPUT TO FILE ONLY** - Write ALL findings to `xss-audit-report.md` (always output report, create with timestamp suffix if exists)
## Search Strategy - 14 Layers (Execute Systematically)
### Layer 1: DOM / HTML Injection Sinks (HTML context)
- Classic HTML injection: innerHTML, outerHTML, insertAdjacentHTML, document.write
- Newer APIs: setHTMLUnsafe, ShadowRoot.innerHTML, attachShadow
- React: dangerouslySetInnerHTML, createElement, cloneElement
- HTML builders: DOMParser, template.innerHTML, createRange
### Layer 2: Attribute & Event Handler Injection (attribute/JS contexts)
- Inline event handlers, dynamic attribute names
- Dangerous attributes: on*, href, src, srcdoc, xlink:href, action, formaction, data, poster, style
- JSX props that can become dangerous
### Layer 3: URL Injection & Navigation (CRITICAL) - EXPANDED
- ALL href/src/action assignments
- ALL window.open calls
- location/document.location assignments & redirects
- History API state changes (pushState, replaceState) and subsequent consumers of the modified URL; these APIs do not themselves load the supplied URL
- Router navigation (React Router, Next.js, etc.)
- Protocol patterns: javascript:, data:, vbscript:, file:, blob: - review in context; their presence alone does not prove XSS
**URL validation anti-patterns (MUST audit for each validation found):**
1. **Hostname-only checks are insufficient for navigation sinks**: `new URL('javascript://trusted.com/%0aalert(1)').hostname` evaluates to `trusted.com`. Protocol and the eventual sink must also be checked; do not assign severity from the validator alone
2. **Substring checks**: `url.includes('trusted.com')` / `url.startsWith('https://trusted.com')` - bypassable via `https://trusted.com.evil.com`, `https://trusted.com@evil.com`, `https://evil.com/?q=trusted.com`
3. **Raw-string comparisons that ignore parser normalization**: prefer comparing the normalized components returned by `new URL()`; if raw strings are compared, check case, whitespace, and control-character handling explicitly
4. **Protocol-relative URLs**: `//evil.com` passing naive checks
5. **Backslash confusion**: `https:\\evil.com` treated as valid by browsers but mismatched by string checks
- Verdict rule: there is no universal "safe URL" rule. Parse with `new URL(input, trustedBase)` or an equivalent standards-based parser, use a protocol allowlist appropriate to the specific element and sink, and compare hostnames exactly or with a dot-boundary suffix check when a domain restriction is required. `http:`/`https:` is a common navigation allowlist, not a universal rule; relative URLs and schemes such as `mailto:`/`tel:` may be legitimate. Confirm attacker control and the final sink before classifying a finding
### Layer 4: Configuration / Content Models & JSON-in-Script (CRITICAL)
- SSR bootstraps: __INITIAL_STATE__, __NEXT_DATA__, __NUXT__, __APOLLO_STATE__
- Configuration objects with url/href/link/html/template
- UI widgets/content blocks with rich text
- External data sources flowing to render models
**JSON-in-script injection:**
- Attacker-influenced data serialized into inline `` can terminate the element early and enable markup/script injection
- Safe patterns to look for: `.replace(/` bodies, `dangerouslySetInnerHTML` on `` breakout
- `JSON.stringify` alone is NOT sufficient inside a `` breakout in `` breakout)
- Sanitizer output unsafely re-parsed, transformed, or concatenated before insertion (mXSS); separately, `ALLOW_DATA_ATTR: true` on framework-bound markup only when the exact Layer 14 binding/compilation chain is present
- `postMessage(sensitiveData, '*')` when the target window can be navigated or controlled by an untrusted origin