Listen to this Post

Introduction:
Cross-Site Scripting (XSS) remains one of the most prevalent and dangerous web vulnerabilities, yet the approach most aspiring bug bounty hunters take is fundamentally flawed. The difference between a hunter who consistently finds XSS vulnerabilities and one who doesn’t lies not in the length of their payload list, but in their understanding of how browsers parse, render, and execute HTML. As Sufiyan SM, an Offensive Security Professional, emphasizes in his training framework, mastering the browser’s HTML parsing mechanics—the “family tree” of the Document Object Model (DOM)—is the true foundation of XSS discovery. This article breaks down the exact methodology taught to mentees, transforming the approach from guessing payloads to reading the page source with precision.
Learning Objectives:
- Understand the HTML DOM hierarchy and how user input lands in different rendering contexts
- Identify the “Dangerous 6” HTML tags that execute JavaScript and their attribute-based variants
- Master the “Breakout” mechanic using quotes, angle brackets, and context termination
- Deploy zero-click XSS triggers using `onerror` and `autofocus` event handlers
- Apply context-aware payload generation and browser parsing logic to real-world bug bounty scenarios
- The HTML “Family Tree”: Where Your Input Actually Lands
The foundational concept that separates effective XSS testing from guesswork is understanding the DOM hierarchy. When user input is reflected in a page, it lands somewhere within this tree—and where it lands determines exactly which payloads will work and which will fail.
Understanding Rendering Contexts
Every piece of user-controlled data that appears in an HTML response exists within one of four primary rendering contexts: HTML body (between tags), HTML attribute (inside a tag’s attribute), URL (within a link or resource reference), or CSS (inside style blocks). Each context has its own parsing rules, encoding requirements, and execution vectors.
For example, input reflected between paragraph tags (<p>
</p></code>) lives in the HTML body context, where you can introduce new tags like `<script>` or <code><img></code>. But if that same input appears inside an attribute like <code><input value="[bash]"></code>, angle brackets may be encoded, and your breakout strategy shifts to terminating the attribute value and introducing event handlers. <h2 style="color: yellow;">Step-by-Step Guide to Mapping the DOM Tree:</h2> <ol> <li>Identify reflection points: Submit a unique string (e.g., <code>xss_test_123</code>) through every input vector—URL parameters, POST fields, headers, cookies, and JSON bodies.</p></li> <li><p>View page source (Ctrl+U or Cmd+Option+U): Locate your test string in the raw HTML response. This reveals the exact context without any client-side JavaScript modifications.</p></li> <li><p>Trace the ancestry: Use browser DevTools (F12 → Elements tab) to inspect the element containing your input. Note the parent tags and attributes surrounding it.</p></li> </ol> <h2 style="color: yellow;">4. Determine the context:</h2> <ul> <li>Between tags? → HTML body context</li> <li>Inside `href` or <code>src</code>? → URL context</li> <li>Inside an event handler like <code>onclick</code>? → JavaScript context</li> <li>Inside a style attribute? → CSS context</li> </ul> <ol> <li>Document the data flow: Map every parameter, its location (URL/body/header), and its rendering context in a spreadsheet.</li> </ol> <blockquote> <p>Pro Tip: Some XSS contexts are only visible after JavaScript execution. Use the `debugger;` statement in the console or the Sources tab to pause execution and inspect dynamically generated DOM elements. </blockquote> <h2 style="color: yellow;">2. The "Dangerous 6" Tags That Execute Code</h2> Not all HTML tags are created equal from a security perspective. Sufiyan's training identifies six primary tags and their variants that can execute JavaScript, forming the core arsenal of any XSS hunter. <h2 style="color: yellow;">The Core Six:</h2> <h2 style="color: yellow;">| Tag | Execution Vector | Example |</h2> <h2 style="color: yellow;">|--|||</h2> | `<script>` | Direct JavaScript execution | `<script>alert(document.domain)</script>` | | `<img>` | `onerror` event when image fails to load | `<img src=x onerror=alert(1)>` | | `<iframe>` | `src` with `javascript:` or `onload` | `<iframe src="javascript:alert(1)">` | | `<svg>` | `onload` or nested script elements | `<svg onload=alert(1)>` | | `<body>` | `onload` or `onpageshow` | `<body onload=alert(1)>` | | `<input>` | `onfocus` + `autofocus` for zero-click | `<input onfocus=alert(1) autofocus>` | <h2 style="color: yellow;">Beyond the Six: Attribute-Based Execution</h2> When tag injection is blocked, event handler attributes become the primary vector. PortSwigger's research highlights that common scriptable contexts include <code>onerror</code>, <code>onload</code>, <code>onclick</code>, <code>onmouseover</code>, <code>onfocus</code>, and <code>oninput</code>. The key insight is that any attribute that accepts JavaScript as a value can be exploited—even in tags that don't typically fire events automatically. <h2 style="color: yellow;">Practical Testing Methodology:</h2> [bash] Use Burp Intruder to enumerate permitted tags Send request to Intruder, position payload in the reflection point Load the XSS cheat sheet tag list: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet Filter results by those that executed without user interaction
Linux/Windows Command for Payload Generation:
Generate context-aware payload variants using Python python3 -c " payloads = [ '<script>alert(1)</script>', '<img src=x onerror=alert(1)>', '<svg onload=alert(1)>', '<input onfocus=alert(1) autofocus>', 'javascript:alert(1)', '\\"><script>alert(1)</script>' ] for p in payloads: print(p) "
- The "Breakout" Mechanic: Why Quotes Are Your Best Weapon
The "Breakout" mechanic is the art of escaping the current context to introduce executable code. When input is reflected inside an HTML attribute value—for instance, <input value="
"></code>—the attacker must first break out of the quoted attribute before introducing new HTML or JavaScript. <h2 style="color: yellow;">Understanding Context Termination:</h2> <ul> <li>Double-quoted attribute: `"` closes the value, `>` closes the tag → `"><script>alert(1)</script>` - Single-quoted attribute: `'` closes the value, `>` closes the tag → `'><script>alert(1)</script>` - Unquoted attribute: Space or `>` terminates the attribute → ` onfocus=alert(1) x=` </li> </ul> <h2 style="color: yellow;">Step-by-Step Breakout Guide:</h2> <ol> <li>Submit a test string containing common break characters: `"'><` </li> <li>Inspect the rendered HTML in DevTools to see which characters were not encoded or filtered.</p></li> <li><p>If quotes pass through: Terminate the attribute and close the tag: `"><script>alert(1)</script>` </p></li> <li>If angle brackets are encoded but quotes are not: Inject a new event handler attribute: `" onfocus=alert(1) autofocus x="` </li> <li><p>If quotes are encoded but angle brackets pass: You're in the HTML body context—introduce new tags directly.</p></li> <li><p>If both are encoded: Look for alternative contexts like URL or JavaScript where different encoding rules apply.</p></li> </ol> <h2 style="color: yellow;">Real-World Example:</h2> <p>Consider a search box that reflects input inside a `<div>` tag's <code>data-attribute</code>: [bash] <div data-search="[USER INPUT]">Results for...</div>
Payload: `" onmouseover="alert(1)" x="`
Result: `
Results for...
`
The double quote breaks out of the attribute, `onmouseover` introduces an event handler, and the trailing `x="` repairs the broken HTML.
> Windows/Linux Command for Filter Testing:
> ```bash
Use curl to test reflected XSS with various break characters
curl "http://target.com/search?q=%22%27%3E%3Cscript%3Ealert(1)%3C/script%3E"
> URL-encoded: " ' >
> ```
4. Zero-Click Triggers: onerror and autofocus
The most valuable XSS vulnerabilities are those that execute without any user interaction—known as zero-click or auto-execution vectors. These are the high-priority findings that command top bounties.
The `onerror` Vector:
The `onerror` event fires when a resource fails to load. By pointing an `` or `
<img src="invalid.jpg" onerror="alert(document.domain)"> <iframe src="about:blank" onerror="alert(1)"></iframe>
This works because the browser parses the tag, attempts to load the resource, fails, and executes the `onerror` handler—all without any user clicking or typing.
The `autofocus` + `onfocus` Combo:
When `onerror` is filtered, the `autofocus` attribute provides an elegant bypass. The `autofocus` attribute automatically gives focus to an input element when the page loads. Combined with the `onfocus` event handler, this creates a zero-click execution:
<input onfocus="alert(1)" autofocus>
The browser focuses the input automatically, triggering `onfocus` and executing the JavaScript.
Step-by-Step Zero-Click Testing:
- Identify a reflection point where you can inject HTML attributes.
-
Test the `onerror` vector first as it's the most commonly overlooked:
<img src=x onerror=alert(1)>
-
If `onerror` is blocked, try the `autofocus` + `onfocus` combination:
<input onfocus=alert(1) autofocus>
-
If both are filtered, explore other auto-triggering events:
`
- `
- ` -
Test with minimal payloads to avoid filter detection:
<img src=1 onerror=alert``>
> Burp Suite Configuration for Zero-Click Testing:
> 1. Send request to Intruder
- Set payload position at the reflection point
- Load a wordlist of event handlers (onerror, onload, onfocus, onmouseover, etc.)
- Add `autofocus` to each payload for automatic triggering
- Monitor responses for execution indicators (alerts, console logs, or DOM changes)
5. Context-Aware Hunting: Beyond the Generic Payload
The same payload will not work everywhere. Advanced XSS hunting requires adapting injections based on where the user input is reflected. This is where understanding browser parsing truly pays dividends.
Context Classification Framework:
| Context | Typical Location | Payload Strategy |
||||
| HTML Body | Between tags | Introduce new tags: <script>, `` |
| HTML Attribute | Inside value=, `data-` | Break out with quotes, inject event handlers |
| URL | href=, `src=` | Use `javascript:` protocol or data URIs |
| JavaScript | Inside `