Skip to content

Node.js Security Checklist — Complete Guide to Secure Application Development

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Node.js Security Checklist. We cover key concepts, practical examples, and best practices to help you master this topic.

Node.js security checklist covers input validation, dependency vulnerability management, HTTP security headers, CORS configuration, Rate Limiting, and protection against OWASP top 10 attacks.

What You'll Learn

By the end of this tutorial, you'll implement a comprehensive security checklist for Node.js applications, configure Helmet and CORS, prevent injection attacks, secure dependencies, and harden production deployments.

Why Security Matters

Node.js applications handle sensitive data and face constant attack attempts. A single vulnerability can lead to data breaches, financial loss, and reputational damage.

Real-World Use

A payment processing API blocks 10,000 malicious requests daily using rate limiting, validates all inputs with Zod schemas, audits dependencies weekly, and uses Helmet headers to prevent XSS and clickjacking.

Security Path

flowchart LR
  A[Docker] --> B[Security Checklist]
  B --> C[Helmet/CORS]
  B --> D[SSRF Protection]
  C --> E[Deployment]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Input Validation and Sanitization

Validate all user inputs with a schema library like Zod or Joi.

const { z } = require("zod");
const userSchema = z.object({
  email: z.string().email(),
  age: z.number().int().positive().max(150),
  name: z.string().min(1).max(100).trim(),
  role: z.enum(["admin", "user", "viewer"]),
});
function createUser(data) {
  const parsed = userSchema.parse(data);
  return parsed; // Safe to use
}
try {
  createUser({ email: "test@example.com", age: 25, name: "Alice", role: "admin" });
} catch (err) {
  console.error("Validation error:", err.errors);
}

Helmet for HTTP Headers

Helmet sets secure HTTP headers to prevent common web vulnerabilities.

const express = require("express");
const helmet = require("helmet");
const app = express();
app.use(helmet());
// Sets: Content-Security-Policy, X-Frame-Options, X-Content-Type-Options
// Strict-Transport-Security, X-XSS-Protection, and more
app.get("/", (req, res) => res.send("Secure!"));
app.listen(3000);

CORS Configuration

Configure CORS to allow only trusted origins.

const cors = require("cors");
const express = require("express");
const app = express();
const allowedOrigins = ["https://myapp.com", "https://admin.myapp.com"];
app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error("Not allowed by CORS"));
    }
  },
  methods: ["GET", "POST", "PUT", "DELETE"],
  allowedHeaders: ["Content-Type", "Authorization"],
  credentials: true,
  maxAge: 86400,
}));

Rate Limiting

Protect against DDoS and brute-force attacks with rate limiting.

const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
  message: { error: "Too many requests, please try again later." },
  standardHeaders: true,
  legacyHeaders: false,
});
const authLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 5,
  message: { error: "Too many login attempts." },
});
app.use("/api/", limiter);
app.use("/api/auth/login", authLimiter);

Dependency Auditing

Regularly audit and update dependencies for known vulnerabilities.

const { execSync } = require("node:child_process");
function auditDependencies() {
  try {
    const result = execSync("npm audit --json", { encoding: "utf8" });
    const report = JSON.parse(result);
    if (report.metadata.vulnerabilities.critical > 0) {
      console.error("CRITICAL vulnerabilities found!");
      console.table(report.vulnerabilities);
      process.exit(1);
    }
    console.log("No critical vulnerabilities");
  } catch (err) {
    const report = JSON.parse(err.stdout);
    console.log(`Found ${report.metadata.vulnerabilities.total} vulnerabilities`);
  }
}
auditDependencies();

Common Mistakes

1. Storing Secrets in Code

API keys, passwords, and tokens in source code end up in version control. Use environment variables or secrets managers.

2. Disabling Helmet for Development

Helmet headers are important even in development. Attackers scan dev environments too.

3. Overly Permissive CORS

CORS: "*" allows any website to make requests to your API. Restrict to specific origins.

4. No Input Validation on File Uploads

Accepting any file type allows malware uploads. Validate MIME types, size limits, and scan for malware.

5. Using eval() or new Function()

Code execution from user input is the most dangerous vulnerability. Never evaluate untrusted code.

Practice Questions

1. What HTTP headers does Helmet set?

Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, X-XSS-Protection, and more.

2. How do you prevent SQL Injection in Node.js?

Use parameterized queries with prepared statements. Never concatenate user input into SQL strings.

3. What is the purpose of CSRF tokens?

Prevent cross-site request forgery by ensuring requests come from legitimate application pages.

4. How should you handle file uploads securely?

Validate MIME type, check file extension, limit file size, scan for malware, store outside web root.

5. Challenge: Implement a security middleware that logs all blocked requests.

function securityLogger(req, res, next) {
  const originalEnd = res.end;
  res.end = function(...args) {
    if (res.statusCode === 403 || res.statusCode === 429) {
      console.warn(`Blocked ${req.method} ${req.path} from ${req.ip} - ${res.statusCode}`);
    }
    originalEnd.apply(this, args);
  };
  next();
}

FAQ

What is the most common Node.js security vulnerability?

Prototype pollution. Occurs when user input modifies Object.prototype, affecting all objects.

How do I protect against prototype pollution?

Use Map instead of plain objects, validate keys, and freeze the prototype with Object.freeze(Object.prototype).

Should I use npm audit in CI?

Yes. Run npm audit in CI and fail builds with critical or high vulnerabilities.

What is the difference between authentication and authorization?

Authentication verifies identity. Authorization determines what the authenticated user can access.

How do I securely store passwords?

Use bcrypt (hash + salt) or argon2. Never store plain text or use MD5/SHA1.

Mini Project: Security Middleware Stack

Build a reusable security middleware stack for Express.

const helmet = require("helmet");
const cors = require("cors");
const rateLimit = require("express-rate-limit");
const { z } = require("zod");
function securityMiddleware(app, options = {}) {
  app.use(helmet(options.helmet));
  app.use(cors(options.cors || { origin: process.env.ALLOWED_ORIGINS?.split(",") || "*" }));
  app.use(rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100,
    ...options.rateLimit,
  }));
  app.use((req, res, next) => {
    res.removeHeader("X-Powered-By");
    next();
  });
}

What's Next

Node.js Helmet CORS Rate Limit Node.js SSRF Protection Node.js Deployment

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro