👉 Most XSS vulnerabilities don't exist because developers are careless… 👉 They exist because developers misunderstand how browsers interpret input.
Let's break it down simply.
🧪 The Problem
You build a simple feature:
<div>${userInput}</div>Seems harmless, right?
Until someone submits:
<script>alert('XSS')</script>Now your app is executing arbitrary JavaScript in users' browsers.
That's Cross-Site Scripting (XSS).
🧠 The Root Cause
The browser doesn't know your intention.
It only sees:
- HTML → render it
- JavaScript → execute it
So when you inject raw user input into HTML, you're essentially saying:
"Browser, interpret this however you like."
That's the mistake.
🛡️ The Fix (Layered, Not Optional)
1️⃣ Escape Output (Non-Negotiable)
Convert special characters into safe text.
const escapeHtml = require("escape-html");
const safe = escapeHtml(userInput);Now:
<script>alert(1)</script>becomes:
<script>alert(1)</script>👉 The browser displays it, not executes it.
2️⃣ Sanitize (Only When Necessary)
If your app allows limited HTML (like <b> or <i>):
const sanitizeHtml = require("sanitize-html");
const clean = sanitizeHtml(userInput, {
allowedTags: ["b", "i"],
});⚠️ But be honest with yourself: Sanitization is fragile if misconfigured.
3️⃣ Content Security Policy (CSP)
Your last line of defense.
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
},
})
);This blocks inline scripts — even if something slips through.
⚠️ Common Mistake
Adding this:
scriptSrc: ["'self'", "'unsafe-inline'"]…completely defeats CSP.
At that point, you're just pretending to be secure.
🔑 The Mindset Shift
Stop asking:
"How do I block XSS?"
Start asking:
"How do I ensure user input is never treated as code?"
That one shift changes everything.
💡 Final Takeaway
Security is not a feature you add later. It's a habit you build into every line of code.
If you're building anything that accepts user input (which is everything):
- Escape by default
- Sanitize when required
- Enforce CSP always
I'm currently diving deeper into cybersecurity from a developer's perspective — breaking things, fixing them, and documenting the lessons.
If you're on the same path, let's connect.