| technology | Node.js | ||||||
|---|---|---|---|---|---|---|---|
| domain | backend | ||||||
| level | Senior/Architect | ||||||
| version | 24+ | ||||||
| tags |
|
||||||
| ai_role | Senior Node.js Security Expert | ||||||
| last_updated | 2026-03-24 |
This document outlines the strict security configurations and anti-patterns that must be mitigated in a production Node.js environment.
// Unsafe recursive object merging
function merge(target, source) {
for (let key in source) {
if (typeof source[key] === 'object') {
if (!target[key]) target[key] = {};
merge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}Unsafe object merging allows attackers to overwrite properties on the global Object.prototype (e.g., via __proto__). This Prototype Pollution leads to application-wide configuration manipulation, privilege escalation, or Remote Code Execution (RCE).
// Safe merging utilizing null-prototype objects and property validation
function safeMerge(target, source) {
for (let key in source) {
if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;
if (typeof source[key] === 'object' && source[key] !== null) {
if (!target[key]) target[key] = {};
safeMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}Note
Internal Routing: For more context, refer back to the Nodejs Index.
STRICTLY filter reserved prototype keys (__proto__, constructor, prototype) during deep clone or merge operations. Alternatively, use robust, community-vetted libraries (like lodash.merge) that have built-in pollution defenses.
// Exposing secrets in code
const dbClient = new Database('postgres://admin:supersecretpassword@db.internal:5432/mydb');Embedding plaintext passwords or API keys directly in source code guarantees a critical security breach if the repository is compromised. Hardcoded secrets persist in Git history forever and expose backend infrastructure to attackers.
// Utilizing environment variables safely
const dbUrl = process.env.DATABASE_URL;
if (!dbUrl) throw new Error('MANDATORY DATABASE_URL config is missing');
const dbClient = new Database(dbUrl);MANDATORY injection of secrets via environment variables or secret management vaults (e.g., AWS Secrets Manager, HashiCorp Vault). NEVER commit sensitive material to version control.
// A vulnerable regex pattern evaluated on user input
const emailRegex = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
app.post('/validate', (req, res) => {
const isValid = emailRegex.test(req.body.email);
res.send({ isValid });
});Using poorly optimized regular expressions with nested quantifiers (Catastrophic Backtracking) allows an attacker to send crafted payloads that block the Node.js event loop entirely. This causes a complete Denial of Service (ReDoS).
// Using a robust, vetted validation library
const validator = require('validator');
app.post('/validate', (req, res) => {
if (typeof req.body.email !== 'string') return res.status(400).send('Invalid format');
const isValid = validator.isEmail(req.body.email);
res.send({ isValid });
});FORBID the use of complex, custom regular expressions on unconstrained user input. STRICTLY utilize established validation libraries and apply input length constraints before regex execution.
graph LR
classDef default fill:#0d1117,stroke:#30363d,stroke-width:2px,color:#c9d1d9;
classDef component fill:#238636,stroke:#2ea043,stroke-width:2px,color:#ffffff;
A[Client Request] --> B[Security Middleware]
B --> C[Validation Layer]
C --> D[Business Logic]
class B,C component;