Key Takeaways

  • Scanners find the easy reflected XSS β€” the bugs that pay real money (stored XSS, DOM XSS, mXSS) require manual hunting
  • Context is everything: the same payload that works in raw HTML fails inside a JavaScript string or tag attribute
  • DOM-based XSS lives entirely in client-side code β€” you find it by reading JavaScript, not by fuzzing parameters
  • WAF bypass is a skill, not a trick: understand what the filter blocks, then find what it allows
  • Impact determines payout β€” escalate from alert(1) to account takeover or data exfiltration before reporting

Why XSS Still Pays in 2026

Cross-site scripting has been on the OWASP Top 10 for over two decades, and it still accounts for roughly 20% of all bug bounty payouts. The reason is simple: every web application reflects user input somewhere, and the attack surface keeps growing as applications move logic to the client side.

But the easy XSS β€” the reflected parameter that pops an alert box β€” gets caught by scanners and fixed before you ever see it. The XSS that pays in 2026 is the kind scanners cannot find: DOM-based injection through client-side JavaScript, stored XSS through multi-step workflows, and mutation XSS that exploits browser parsing quirks to bypass sanitizers.

This guide covers how to find those bugs. If you're looking for what automated scanners check, read our reflected XSS scanner detection guide first. This article picks up where scanners stop.

The Three Types of XSS (And Which Ones Pay)

Reflected XSS

The input goes in through a request parameter and comes back in the immediate response. The victim must click a crafted link. Reflected XSS on a login page or sensitive action page pays Medium. On a static marketing page, most programs mark it Low or Informational.

Scanners catch most reflected XSS. Your edge as a manual hunter is finding reflections in unusual places: HTTP headers rendered in error pages, JSON responses consumed by client-side rendering, and API endpoints whose output gets injected into the DOM by frontend code.

Stored XSS

The payload persists on the server and executes when other users view the affected page. This is where the money is. A stored XSS in a user profile field that renders on an admin dashboard can be Critical. Common injection points:

The key insight: the injection point and the execution point are often on different pages, accessed by different user roles. Scanners test the same page they inject into β€” they miss cross-page stored XSS entirely.

DOM-Based XSS

The payload never reaches the server. Client-side JavaScript reads from a source (URL fragment, localStorage, postMessage) and writes to a dangerous sink (innerHTML, document.write, eval). The server response is clean β€” the vulnerability exists entirely in the browser.

This is the most underreported XSS type because it requires reading JavaScript source code, not just fuzzing parameters. If you develop the skill to trace source-to-sink data flows in client-side code, you will find bugs that no other hunter and no scanner will catch.

Step 1: Map Every Input Reflection Point

Before you test a single payload, map where user input appears in the application's output. This is not just URL parameters β€” it includes:

Use Burp Suite's passive scanner to flag reflections automatically as you browse. For a more targeted approach, inject a unique canary string (like xss7r4c3) into every parameter and search the response for it. This tells you where your input lands without triggering any WAF rules.

Step 2: Identify the Rendering Context

The same input reflected in different HTML contexts requires completely different payloads. Before crafting an exploit, determine exactly where your input lands:

ContextExampleBreakout Strategy
Raw HTML<div>USER_INPUT</div>Inject a tag directly: <img src=x onerror=alert(1)>
Tag attribute (quoted)<input value="USER_INPUT">Close the attribute and tag: "><img src=x onerror=alert(1)>
Tag attribute (unquoted)<input value=USER_INPUT>Add an event handler: x onfocus=alert(1) autofocus
JavaScript stringvar x = 'USER_INPUT';Close the string: ';alert(1)//
Template literalvar x = `USER_INPUT`;Expression injection: ${alert(1)}
HTML comment<!-- USER_INPUT -->Close the comment: --><img src=x onerror=alert(1)>
CSS valuebackground: url(USER_INPUT)Limited in modern browsers β€” focus on other contexts

If you send a generic <script>alert(1)</script> payload into an attribute context, it will fail even if there is zero sanitization. Context-aware payloads are not optional β€” they are the difference between finding the bug and missing it.

Step 3: Hunt DOM-Based XSS

DOM XSS requires a different methodology. You are not testing server responses β€” you are auditing client-side JavaScript.

Dangerous Sinks to Search For

Open the browser DevTools, go to Sources, and search the application's JavaScript for these patterns:

Tainted Sources to Trace

For each sink, trace backward to find where the data originates:

If user-controlled data flows from a source to a sink without sanitization, you have a DOM XSS. Burp Suite's DOM Invader extension automates source-to-sink tracing and is worth the Professional license cost for this alone.

Step 4: Bypass WAFs and Sanitizers

Modern applications use WAFs (Cloudflare, AWS WAF, Akamai) and client-side sanitizers (DOMPurify). When your payload gets blocked, don't give up β€” adapt.

WAF Bypass Techniques

Use alternative tags. WAFs often block <script>, <img>, and <svg> but miss less common tags:

<details open ontoggle=alert(1)>
<math><mtext><table><mglyph><style><!--</style><img src=x onerror=alert(1)>
<svg/onload=alert(1)>
<body onpageshow=alert(1)>
<marquee onstart=alert(1)>

Use alternative event handlers. If onerror and onload are blocked:

onfocus, onblur, oninput, onchange
onanimationstart, onanimationend
onbeforetoggle (new in 2025+)
onpointerover, onpointerenter

Encoding and case tricks:

Client-Side Sanitizer Bypass (Mutation XSS)

DOMPurify is the gold standard for client-side sanitization, but older versions have known mXSS vectors. When you encounter DOMPurify:

  1. Check the version (look in the JavaScript source or network responses)
  2. Search for known bypasses for that version on PortSwigger Research and the DOMPurify GitHub issues
  3. Test with nested tag combinations that the browser's parser normalizes differently than the sanitizer expects

Mutation XSS is rare but pays extremely well because it bypasses the defense that the application explicitly chose to deploy.

Step 5: Escalate Impact

A report that says "I can execute alert(1)" gets triaged as Low. A report that says "I can take over any user's account" gets triaged as Critical. Same vulnerability, different payout. Always escalate before reporting.

Impact Escalation Paths

Document the full attack chain in your report. Include the payload, the impact proof, and a clear explanation of what an attacker could achieve. See our bug bounty report writing guide for the full template.

XSS Hunting Checklist

  1. Map all reflection points (parameters, headers, cookies, fragments)
  2. Inject canary strings to identify where input appears in output
  3. Determine the rendering context for each reflection
  4. Test context-specific breakout payloads
  5. Audit client-side JavaScript for source-to-sink DOM XSS
  6. Test stored XSS through profile fields, comments, file metadata
  7. Attempt WAF bypass with alternative tags and event handlers
  8. Check for mutation XSS if client-side sanitization is present
  9. Escalate impact: session hijacking, token theft, or action-as-victim
  10. Write the report with full attack chain and business impact

Tools for XSS Hunting

ToolPurposeCost
Burp Suite ProfessionalPassive reflection detection, active scanning, Turbo Intruder for payload fuzzing$449/yr
DOM Invader (Burp extension)Automated source-to-sink tracing for DOM XSSIncluded with Burp Pro
dalfoxOpen-source XSS scanner with context-aware payload generationFree
XSStrikeFuzzing engine that analyzes context and generates targeted payloadsFree
Browser DevToolsJavaScript debugging, DOM inspection, network analysisFree
kxssFast reflection checker β€” identifies which parameters reflect unfilteredFree

For a deeper look at Burp extensions that accelerate XSS hunting, see our Burp Suite extensions guide.

Common Mistakes That Waste Time

What to Read Next

XSS hunting pairs well with other client-side and injection-focused skills:

Advertisement