Introduction

What's up, hackers! 👋

I'm excited to share this writeup about a Reflected XSS vulnerability I discovered during my bug bounty hunting journey. This find really reinforced an important lesson I've learned: the simplest features often hide the most critical vulnerabilities.

This bug was sitting right there in plain sight — the search bar. You know, that innocent-looking text box that everyone uses to find products? Yeah, that one. Most people type product names into it. I typed something completely different.

What made this vulnerability interesting wasn't just finding the XSS itself — it was how the injection worked. The user input was reflected inside an existing <script> tag, which meant I couldn't just throw a basic payload at it. I had to break out of the JavaScript context first before I could execute my code.

Let me walk you through exactly how I found it.

The Hunt Begins: Step 1 — Finding the Reflection

I landed on the target website and started doing what I always do — looking for input fields. Login forms, comment sections, contact forms… and then I saw it: the search bar.

Search functionality is a goldmine for XSS hunters because:

  • It's designed to accept any user input
  • Results pages often reflect that input back to show what you searched for
  • Developers sometimes overlook it because "it's just a search"

I started simple. No fancy payloads yet — just a basic test string:

test

Hit enter. The page refreshed and showed:

Search results for: "test"

My input was reflected directly in the HTML response.

That's step one. Now I needed to know: is there any filtering happening?

Step 2: Testing for Sanitization

Time to throw some special characters at it and see what sticks. I tried:

test><" '

These characters are critical in web attacks:

  • < and > → Used to create HTML tags
  • " and ' → Used to break out of attributes
  • If these aren't encoded, we might have a vulnerability

The page responded:

Search results for: "test><" '"

No encoding. No filtering. Nothing.

All the dangerous characters came back untouched. This was looking very promising.

Step 3: Locating the Injection Point with Burp Suite

Now here's where most people stop — they see the reflection in the visible page content and think that's the only place it exists. Big mistake.

I opened up Burp Suite and used a unique identifier to track exactly where my input was landing in the raw HTML response:

test3030

Request:

GET /search?q=test3030%3E%3C%22+%27&search-button=&lang=en_US HTTP/2
Host: [REDACTED]

I searched the response for test3030 and found something interesting: my input was reflected in multiple places, some filtered, some not.

Then I found the jackpot — buried inside the page source:

Response:

}]);
pushMCView(["trackPageView",{
    "search":"test3030><\" '"
}]);
flushViewQueue();
} catch (e) { console.error(e); }
</script>

🔍 My input was sitting inside an existing <script> block - completely unfiltered.

None

As you can see in the screenshot, the search parameter test3030><\" ' is reflected directly inside the JavaScript pushMCViewfunction without any sanitization. The special characters are all there - unencoded and ready for exploitation.

This is different from a typical XSS. My input isn't in the HTML body — it's inside JavaScript code. That means I need a different approach.

Step 4: Breaking Out of the Script Context

Here's the problem: I can't just inject <img src=x onerror=alert(1)> because I'm already inside a <script> tag. The browser is expecting JavaScript syntax, not HTML.

But then I realized something: what if I close the script tag myself?

I tested:

</script>test3030

What happened?

The browser saw the closing </script> tag and ended the JavaScript context right there. Everything after it was now treated as HTML, not JavaScript.

I successfully escaped the script context.

Let me verify this with Burp Suite:

Request:

GET /search?q=</script>test3030%3E%3C%22+%27&search-button=&lang=en_US HTTP/2

Response:

pushMCView(["trackPageView",{
    "search":"</script>test3030><\" '"
}]);
flushViewQueue();
} catch (e) { console.error(e); }
</script>
None

Perfect! As shown in the screenshot, my </script> tag successfully closes the existing script block early. The browser now interprets everything after </script> as HTML content, not JavaScript. This is the key to the exploit.

Now I could inject arbitrary HTML elements — and with them, JavaScript event handlers.

Step 5: Crafting the Exploit Payload

Time to build the final payload. My strategy:

  1. Close the existing <script> tag with </script>
  2. Inject an SVG element (lightweight, always works)
  3. Use the onload event to execute JavaScript

Final Payload:

</script><svg/onload=alert(document.domain)>

Full malicious URL:

/search?q=</script><svg/onload=alert(document.domain)>&search-button=&lang=en_US

I sent the request through Burp Suite and inspected the response:

Response:

pushMCView(["trackPageView",{
    "search":"</script><svg/onload=alert(document.domain)><\" '"
}]);
None

Excellent! The screenshot confirms that our complete XSS payload </script><svg/onload=alert(document.domain)> is now embedded in the HTML response. The syntax highlighting even shows the </script> tag in red, indicating the script context has been terminated. The SVG element with its malicious onload handler is ready to execute.

Perfect. The payload was in there, unmodified, ready to execute.

Step 6: Proof of Concept — JavaScript Execution

Theory is great, but I needed visual proof. I opened a browser and navigated to the malicious URL.

🎯 The alert box popped up, showing the target domain.

None

And there it is — the moment of truth! The alert dialog displays the target domain, proving we have full JavaScript execution capability in the context of the vulnerable website. Notice how the search results page still shows our payload in the search query, and the URL bar contains our exploit. This is a live, working XSS vulnerability.

Success. I had full JavaScript execution in the context of the target website.

Why This Works

Let me explain exactly what's happening behind the scenes.

My Input:

</script><svg/onload=alert(document.domain)>

How it appears in the HTML:

<script>
pushMCView(["trackPageView",{"search":"</script>  ← Script ends HERE
<svg/onload=alert(document.domain)>               ← This becomes HTML!
"}]);
</script>

What the browser sees:

  1. Start of a <script> block
  2. Some JavaScript code: pushMCView(["trackPageView",{"search":"
  3. Closing script tag: </script> ← Browser thinks the script is done
  4. HTML content: <svg/onload=alert(document.domain)> ← This executes
  5. Random text: "}]); (browser ignores this)
  6. Another </script> tag (browser ignores - no matching open tag)

The browser's HTML parser is greedy — as soon as it sees </script>, it closes the JavaScript context. The application intended for the script to continue, but we hijacked that intention.

Impact

This vulnerability allows an attacker to:

  • Execute arbitrary JavaScript in the victim's browser
  • Steal session cookies (if not protected with HttpOnly)
  • Perform actions on behalf of the user
  • Launch phishing attacks within the trusted domain

Mitigation

To prevent this issue:

  • Properly encode user input before embedding it in JavaScript
  • Use safe serialization methods (e.g., JSON.stringify)
  • Avoid directly injecting user input into script blocks
  • Implement Content Security Policy to reduce exploitation impact

Vulnerability Details

Vulnerability Type: Reflected XSS
Parameter: q
Endpoint: /search
Method: GET
Payload: </script><svg/onload=alert(document.domain)>

Conclusion

This hunt reminded me why I love bug bounties: you never know what you'll find when you start poking around. A simple search bar turned into a full XSS vulnerability

The key takeaways?

  • Always test user input fields — even the "boring" ones
  • Use the right tools (Burp Suite is essential)
  • Understand injection context before crafting payloads
  • Simple is often better than complex

Thanks for reading! I hope this writeup helps you in your own bug hunting journey. Stay curious, stay persistent, and happy hacking! 🔐

#BugBounty #XSS #WebSecurity #HackerOne #EthicalHacking #Pentesting #InfoSec