In September 2024, a security researcher discovered a stored cross-site scripting vulnerability in a major email platform that allowed attackers to execute arbitrary JavaScript the moment a victim opened a crafted message. No clicks required beyond reading the email. The vulnerability sat unpatched for weeks. If you think XSS is a relic of the early web, I need you to reconsider — it remains one of the most exploited vulnerability classes in production applications today.
This post is cross-site scripting explained the way it actually matters: not as an abstract textbook concept, but as a weapon threat actors use daily to steal credentials, hijack sessions, deliver malware, and bypass security controls your organization paid good money to implement. I'll walk you through the three main types, show you real-world impact, and give you the specific defensive steps that actually work.
What Is Cross-Site Scripting (XSS)?
Cross-site scripting is a web application vulnerability that lets an attacker inject malicious scripts — almost always JavaScript — into content that other users view. When the victim's browser renders that content, it executes the attacker's code as if it came from the trusted site. The browser can't tell the difference between legitimate page scripts and the injected payload.
That's the core problem. Your browser trusts the domain. The domain serves tainted content. The attacker's script now runs with the same privileges as the real application code. It can read cookies, capture keystrokes, redirect users, modify page content, and exfiltrate session tokens.
OWASP has ranked injection flaws — including XSS — among the top web application risks for over a decade. The 2021 OWASP Top 10 placed Cross-Site Scripting under the broader "Injection" category at position A03, reflecting its continued prevalence. According to the CISA cyber threats advisory page, injection vulnerabilities remain a top exploitation vector across critical infrastructure sectors.
The Three Types of XSS Attacks You Need to Know
Not all cross-site scripting works the same way. Understanding the three distinct types helps your developers fix the right problems and helps your security team test for the right weaknesses.
Reflected XSS: The Drive-By Attack
Reflected XSS is the most common type. The attacker crafts a malicious URL containing a script payload in a parameter — a search query, an error message, a redirect path. When the victim clicks that link, the server reflects the payload back in the HTTP response without sanitizing it. The victim's browser executes the script immediately.
Here's what this looks like in practice. An attacker sends a phishing email containing a link to your organization's legitimate search page, but the search term parameter contains JavaScript. Your employee clicks the link, sees your real domain in the address bar, and trusts it. Meanwhile, the injected script has already stolen their session cookie and sent it to the attacker's server.
This is where social engineering and XSS intersect. A convincing phishing email plus a reflected XSS vulnerability equals credential theft at scale. Your employees need to recognize suspicious links even when they point to familiar domains — and that's exactly the kind of judgment that phishing awareness training for organizations builds.
Stored XSS: The Persistent Threat
Stored XSS is more dangerous because the payload persists on the server. An attacker submits malicious script through a form — a comment field, a user profile, a support ticket, a forum post — and the application saves it to the database. Every user who views that content gets hit. No phishing link required.
The British Airways breach in 2018 involved a Magecart attack that injected malicious scripts into the airline's payment page. While technically a supply-chain injection, the mechanism was identical to stored XSS: the browser executed attacker-controlled JavaScript on a trusted page, skimming payment card details from approximately 380,000 transactions. The UK's Information Commissioner's Office initially announced a £183 million fine, later reduced to £20 million.
Stored XSS scales effortlessly. One successful injection can compromise thousands of users without the attacker lifting another finger.
DOM-Based XSS: The Client-Side Ambush
DOM-based XSS never touches the server. The vulnerability lives entirely in client-side JavaScript. The application's own scripts read data from an attacker-controlled source — the URL fragment, local storage, or a referrer header — and write it into the DOM without sanitization.
This type is harder to detect with traditional server-side security tools because the malicious payload never appears in HTTP request or response bodies. Your web application firewall won't see it. Your server logs won't capture it. You need client-side analysis and careful code review to find these flaws.
Why XSS Still Dominates the Vulnerability Landscape
The Verizon 2024 Data Breach Investigations Report highlighted that web application attacks accounted for a significant portion of breaches, with stolen credentials and vulnerability exploitation as the primary vectors. XSS is a force multiplier for both — it steals the credentials and exploits the vulnerabilities.
Here's why XSS persists despite being well-understood:
- Developer knowledge gaps. Many developers learn XSS in theory but don't internalize output encoding as a reflex. They rely on frameworks to handle it, then bypass those protections when building custom components.
- Massive attack surface. Every input field, URL parameter, HTTP header, and third-party script inclusion is a potential injection point. Modern single-page applications with dynamic DOM manipulation have made the surface area even larger.
- Third-party dependencies. Your application might be clean, but that analytics script, chat widget, or ad network you embedded? If they're compromised, their code runs with full access to your page. This is essentially a supply-chain XSS vector.
- Underestimation. Security teams sometimes classify XSS as "medium" severity because it requires user interaction. That's a mistake. A stored XSS vulnerability in an admin panel can lead to full application takeover.
Cross-Site Scripting Explained: What Attackers Actually Do With It
Let me break down the real-world attack chains I've seen built on XSS vulnerabilities. These aren't theoretical — they're what threat actors execute daily.
Session Hijacking
The attacker's script reads document.cookie and sends the session token to an external server. The attacker replays that token and takes over the user's authenticated session. If the application doesn't bind sessions to IP addresses or use other fingerprinting, this is trivially easy.
Credential Harvesting
The injected script overlays a fake login form on the legitimate page. The user sees the real domain, the real SSL certificate, and the real branding. They enter their password. The script captures it and sends it to the attacker before submitting the real form so the user never notices.
Keylogging
A persistent XSS payload can attach an event listener to every keystroke on the page. Everything the user types — passwords, credit card numbers, personal messages — gets exfiltrated in real time.
Malware Delivery
The script redirects the browser to a malware download page or silently loads an exploit kit. Because the redirect originates from a trusted domain, URL-based security filters often let it through. This is how XSS becomes a ransomware delivery mechanism.
Privilege Escalation
If an admin user triggers the XSS payload, the attacker's script can use the admin's session to create new admin accounts, modify application settings, or exfiltrate the entire user database. One stored XSS in a ticketing system can compromise everything.
How to Defend Against Cross-Site Scripting
Defense against XSS requires layers. No single control is sufficient. Here's what actually works.
Output Encoding: The Non-Negotiable Foundation
Every dynamic value rendered in HTML, JavaScript, CSS, or URL contexts must be encoded for that specific context. HTML entity encoding handles the HTML body. JavaScript string escaping handles inline scripts. URL encoding handles query parameters. Using the wrong encoding for the context is almost as bad as no encoding at all.
Modern frameworks like React, Angular, and Vue auto-encode output by default. But the moment a developer uses dangerouslySetInnerHTML, bypassSecurityTrust, or v-html, those protections vanish. Code review must flag these bypass patterns aggressively.
Content Security Policy (CSP)
A strict Content Security Policy tells the browser which scripts are allowed to execute. A well-configured CSP blocks inline scripts, restricts script sources to known domains, and uses nonces or hashes to whitelist specific script blocks.
The NIST cybersecurity resource pages reference CSP as a recommended mitigation for injection attacks. But CSP is only effective when it's strict. A policy that includes unsafe-inline or unsafe-eval provides almost no XSS protection. Audit your CSP headers quarterly.
Input Validation
Validate all input on the server side. Reject or sanitize values that contain unexpected characters. But understand this: input validation is a defense-in-depth measure, not a primary XSS control. You cannot reliably filter all possible XSS payloads through input validation alone — output encoding is what actually prevents execution.
HTTPOnly and Secure Cookie Flags
Mark session cookies as HTTPOnly so JavaScript cannot read them. Mark them as Secure so they're only transmitted over HTTPS. This won't prevent all XSS impact — the attacker can still modify the page and capture credentials — but it blocks the most common session hijacking technique.
Multi-Factor Authentication
Even if an attacker steals a session token or captures a password via XSS, multi-factor authentication adds a barrier. It doesn't fix the vulnerability, but it limits the blast radius of credential theft. MFA is a compensating control, not a substitute for fixing XSS.
Regular Security Testing
Run dynamic application security testing (DAST) scans that specifically probe for reflected and stored XSS. Supplement automated scans with manual penetration testing — DOM-based XSS often escapes automated tools. Integrate static analysis (SAST) into your CI/CD pipeline to catch dangerous output patterns before they reach production.
The Human Layer: Why Security Awareness Training Matters for XSS
Here's something most technical write-ups skip: your employees are the last line of defense when XSS exploits succeed. A reflected XSS attack almost always starts with a phishing email or a malicious link delivered through social engineering. If your people can spot the bait, the XSS payload never fires.
I've seen organizations pour resources into application security scanning while ignoring the humans clicking the links. That's a gap threat actors exploit every day. Building a culture of security awareness means your employees question unexpected links, report suspicious emails, and understand that a legitimate-looking domain doesn't guarantee legitimate content.
Start with comprehensive cybersecurity awareness training that covers real attack scenarios — not just checkbox compliance modules. Your people should understand how XSS-laden links are delivered, why they look trustworthy, and what to do when something feels off.
Quick-Reference XSS Prevention Checklist
Pin this somewhere your development and security teams can see it:
- Encode all dynamic output using context-appropriate encoding (HTML, JavaScript, URL, CSS).
- Deploy a strict CSP without
unsafe-inlineorunsafe-eval. - Set HTTPOnly and Secure flags on all session cookies.
- Validate input server-side using allowlists when possible.
- Audit third-party scripts — every external include is a potential XSS vector.
- Scan regularly with both DAST and SAST tools.
- Penetration test manually for DOM-based XSS at least annually.
- Train your people to recognize the phishing emails that deliver XSS payloads.
- Implement multi-factor authentication to limit the impact of stolen sessions.
- Adopt a zero trust model — never assume internal network traffic or authenticated sessions are safe.
XSS Isn't Going Away — But Your Exposure Can Shrink
Cross-site scripting has been a top web vulnerability for over twenty years. It survived the transition from server-rendered pages to single-page applications. It adapted from simple alert box demos to full credential harvesting platforms. And it will keep evolving as web technology changes.
Your job isn't to eliminate XSS from the internet. Your job is to eliminate it from your applications, reduce its impact through layered controls, and train your people to recognize the social engineering that delivers it. Fix the code. Harden the browser. Educate the human.
That combination — technical controls plus security awareness — is what separates organizations that read about data breaches from organizations that become them. Start building both layers today.