█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/JavaScript (Standalone Deep Dive)/JavaScript Security
45 minAdvanced

JavaScript Security

After this lesson, you will be able to: Recognise XSS, CSRF, prototype pollution, and dependency vulnerabilities; read npm audit output.

Most JS security issues are well-known and well-mitigated, IF you know what to look for.

Prerequisites:Testing JavaScript

XSS (Cross-Site Scripting)

Attacker injects script via user input that's rendered as HTML. Reflected: in URL query → echoed to page (search results page). Stored: in DB → rendered for many users (forum post). DOM-based: client-side JS reads attacker-controlled value and inserts into DOM. Defense: React/Vue/Svelte escape by default. Use `dangerouslySetInnerHTML` ONLY with sanitized HTML (DOMPurify). Set CSP header to block inline scripts.

CSRF (Cross-Site Request Forgery)

Attacker tricks the user's browser into making an authenticated request to your site (the browser auto-attaches cookies). Defense: SameSite cookies (default Lax in modern browsers blocks cross-origin POSTs), CSRF tokens, or Origin header checks. LastWrite's middleware enforces Origin check on every mutation, see src/proxy.ts.

Prototype pollution

Less common but devastating. Read this twice.

tsx
// Unsafe merge
function merge(target, source) {
for (const key in source) {
if (typeof source[key] === "object") {
merge(target[key] = target[key] || {}, source[key]);
} else {
target[key] = source[key];
}
}
}
// Attacker sends JSON:
const evil = JSON.parse('{"__proto__":{"admin":true}}');
merge({}, evil);
// Now EVERY object inherits .admin = true (via Object.prototype)
console.log({}.admin); // true
// Defense: Object.freeze(Object.prototype); use safe libraries (lodash 4.17.21+); validate keys.

npm audit + dependency hygiene

Run on every install; pair with Dependabot.

bash
npm audit # shows known vulns in dependencies
npm audit --omit=dev # production only
npm audit fix # auto-fix (within semver range)
npm audit fix --force # force upgrade, read the diff first
# Filter by severity
npm audit --audit-level=high
# In CI:
# - run: npm audit --audit-level=critical
# Combine with Dependabot for automated PRs on new vulns.
# Snyk + GitHub Advanced Security give richer info; paid but worth it at scale.

Common mistakes only experienced JS devs avoid

Using `eval` or `new Function` on user input. Always wrong. Trusting JSON.parse blindly without validating shape. Use Zod. Storing JWT in localStorage. XSS = token theft. Use httpOnly cookies. Ignoring npm audit. CVEs accumulate; one of them eventually hits production.

Quick Check

Why is storing JWT in localStorage a bad idea?

Pick the security reason.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Testing JavaScript
Back to JavaScript (Standalone Deep Dive)
Passion Project: Publish a JS Library→