Blog
Node.js security patterns every code reviewer should enforce
Code Review Tips
Alex Mercer
Jan 30, 2026
Node.js powers millions of applications. It handles multiple tasks at once, which makes it fast and efficient for web applications and servers.
But this approach creates security challenges developers need to address. Errors that aren't handled properly crash the entire application. Missing checks on user input create vulnerabilities. Improper cleanup of resources opens the door to attacks.
Code review is where these patterns get enforced. Here's what every Node.js reviewer should check.
TLDR
Keeping Node.js apps secure comes down to a few basics: handle errors properly, validate all input, keep dependencies in check, and clean up resources. More than half of Node.js security issues come from third-party packages, so dependency changes deserve extra attention. During review, teams should look for missing promise error handling, unvalidated input, forgotten cleanup paths, and risky dependency updates. cubic helps by automatically enforcing these checks across every pull request.
What are the Node.js security patterns every code reviewer should enforce?
Code reviewers should consistently enforce the following security patterns in every Node.js codebase. These are the core security patterns every Node.js code reviewer should enforce:
Error handling patterns that prevent crashes
Node.js handles many operations at the same time. This makes error handling complex. Missing error handlers turn recoverable problems into complete application crashes.
1. Every promise needs error handling
Unhandled promise rejections crash Node.js processes in modern versions. Code creating promises without .catch() handlers or try-catch blocks around await creates a crash risk
javascript
// Unsafe - crashes on error
fetchData().then(process);
// Safe - handles errors
fetchData()
.then(process)
.catch(handleError);
Review should flag any promise chain lacking error handling.
2. Network operations need explicit error handlers
HTTP servers, WebSocket connections, TLS sockets, and database connections all emit error events. Missing error handlers on these EventEmitters crash processes when errors occur.
javascript
// Unsafe - crashes on connection error
const server = http.createServer(handler);
// Safe - handles connection errors
const server = http.createServer(handler);
server.on('error', handleError);
Review should verify error handlers exist for all network-facing code.
3. Errors shouldn't expose sensitive data
Error messages and stack traces often contain database queries, file paths, API keys, or user data. Returning detailed errors to clients leaks information that attackers use.
Code should log detailed errors server-side but return generic messages to clients. Review should catch error responses containing sensitive details.
Input validation patterns that prevent injection
External input cannot be trusted. Size, format, type, and content all need validation before processing.
1. Validate input before database queries
SQL injection remains a top vulnerability. Parameterized queries prevent injection, but the review should verify that queries use parameters correctly.
javascript
// Unsafe - SQL injection risk
db.query(`SELECT * FROM users WHERE id = ${userId}`);
// Safe - parameterized query
db.query('SELECT * FROM users WHERE id = ?', [userId]);
NoSQL databases have similar injection risks. Review should check that user input doesn't get concatenated into queries.
2. Check and clean user input before file access
Path traversal attacks use input like ../../etc/passwd to access files outside intended directories. File operations need path validation.
javascript
// Unsafe - path traversal risk
fs.readFile(userProvidedPath);
// Safe - validates path
const safePath = path.join(baseDir, path.basename(userProvidedPath));
fs.readFile(safePath);
The code review tool should verify that file paths come from validated input, not directly from user requests.
3. Validate input before running system commands
Command injection happens when user input gets passed to child processes. Input needs validation or, better, avoid shell execution entirely.
javascript
// Unsafe - command injection risk
exec(`convert ${userFile} output.png`);
// Safe - uses argument array
execFile('convert', [userFile, 'output.png']);
Review should flag any exec() or eval() with user-provided input.
4. Check request size limits
Large payloads cause denial of service through memory exhaustion. Request size limits prevent attackers from crashing servers with massive inputs.
Middleware like express.json({ limit: '10kb' }) enforces limits. Review should verify that limits exist on all input-accepting endpoints.
Dependency management patterns that reduce supply chain risk
Most Node.js projects rely on third-party packages, and research shows that roughly 70% of apps contain flaws in these dependencies, making careful review essential.
This is where traditional AI code reviewers fall short. Most tools only analyze the code changed in a pull request. cubic goes further by continuously automatically scanning the entire codebase, including transitive dependencies, to detect suspicious changes, hijacked packages, and supply-chain risks that never appear in a single PR.
Reviewers should enforce the following dependency management patterns:
1. Scrutinize new dependencies
Every new package in package.json introduces risk. The review should question whether the dependency is necessary and whether it's from a trusted publisher.
Check package age, download counts, GitHub stars, and maintenance activity. Newly published packages or packages with few users warrant extra scrutiny.
2. Review dependency updates carefully
Package updates might contain breaking changes or vulnerabilities. Lock file changes should be intentional, not automatic bot updates merged without review.
When package-lock.json changes, verify the update is expected and comes from trusted sources.
3. Run security audits before the merge
npm audit identifies packages with known CVEs. Automated code checks catch these before code reaches production.
The review should include audit results and verify that vulnerabilities either get fixed or have documented risk acceptance.
4. Minimize dependency trees
Large dependency trees increase supply chain risk. Each transitive dependency is a potential attack vector.
Review should favor packages with minimal dependencies over those pulling in dozens of transitive packages.
Resource cleanup patterns that prevent leaks
Resource leaks enable denial of service attacks. Proper cleanup on all code paths prevents these issues.
1. Close connections on all paths
Database connections, file handles, network sockets, and timers must be closed. This includes normal completion, error paths, and timeout scenarios.
javascript
// Unsafe - leaks on error
const conn = await db.connect();
await conn.query(sql);
conn.close();
// Safe - cleanup on all paths
const conn = await db.connect();
try {
await conn.query(sql);
} finally {
conn.close();
}
Review should trace resource allocation through all execution paths and verify that cleanup happens.
2. Clear timers and intervals
Uncanceled timers prevent garbage collection. Long-running processes accumulate timers that consume memory.
Code setting intervals or timeouts needs cleanup logic when work completes or errors occur.
3. Handle stream cleanup
Streams need explicit cleanup. Unhandled stream errors crash processes. Unclosed streams leak file descriptors.
Review should verify streams have error handlers and get destroyed when no longer needed.
Authentication and authorization patterns
Access control bugs are common in Node.js applications. Consistent pattern enforcement prevents unauthorized access.
1. Verify authentication on all protected routes
Middleware handles authentication for route groups, but new routes sometimes bypass middleware. Review should verify protected routes and check authentication.
Missing authentication checks on admin routes or API endpoints expose sensitive functionality.
2. Check authorization at the resource level
Authentication confirms identity. Authorization confirms permission. Code that checks "is the user logged in?" without checking "can this user access this resource?" creates privilege escalation risk.
Review should verify that authorization checks happen for every protected resource access.
3. Use secure session management
Session cookies need httpOnly, secure, and sameSite flags. Session IDs should be cryptographically random and rotated after authentication.
Review should check session configuration and verify secure practices.
How cubic enforces these patterns automatically
Manual review of security patterns is time-consuming and inconsistent. Automated code review handles pattern enforcement while humans focus on logic.
1. Define patterns as custom policies
Teams write policies in natural language. "All promises must have error handlers." "Database queries must use parameterized statements." "File operations must validate paths."
cubic enforces these policies automatically on every PR. No manual checking required.
2. Repository-wide analysis catches cross-file issues.
When one file creates a resource, and another should clean it up, cubic traces the relationship. For complex codebases, microservices code reviews, cross-file analysis catches issues that file-focused tools miss.
3. Learning reduces false positives
The false positive problem that affects most AI reviewers gets solved through learning. cubic adapts to your codebase patterns and improves accuracy over time.
4. Scales with team growth
As team size and PR volume grow, manual security review doesn't scale. Automated pattern enforcement maintains consistency regardless of review load.
Enterprise teams need more than bug detection. They need consistent security pattern enforcement across all code.
Implementing security review practices
Secure code reviews in 2026 require systematic approaches, not ad-hoc checks.
1. Create a security checklist
Document the patterns your team enforces. Make it part of the review process. Update it when new patterns emerge, or incidents reveal gaps.
2. Automate what you can
Pattern enforcement through tools like cubic catches issues automatically. Reviewers focus on context-specific security concerns that need human judgment.
3. Train reviewers on common patterns
Not every reviewer knows all security patterns. Training ensures the team understands what to look for and why it matters.
4. Review security-sensitive code more thoroughly
Authentication, authorization, payment processing, and data handling warrant extra scrutiny. Allocate more review time to these areas.
Consistent security checks reduce Node.js vulnerabilities
Node.js security depends on consistent pattern enforcement. Error handling, input validation, dependency management, and resource cleanup need to happen correctly on every PR.
Manual review catches some issues but misses others due to time constraints, expertise gaps, or reviewer fatigue. Automated enforcement through custom policies catches patterns consistently.
AI-code review tool, cubic enforces Node.js security patterns automatically through policies that teams define once and apply everywhere. The system learns from your codebase and improves accuracy over time.
Ready to enforce Node.js security patterns automatically?
Book a demo with cubic to see how custom policies catch vulnerabilities before merge.
