Node.js Security Checklist: OWASP for API Developers
A working security checklist for Node.js APIs, mapped to the OWASP API Top 10 — authorisation, injection, dependencies, secrets and the headers in between.
Security reviews of Node APIs find the same issues so consistently that a checklist is genuinely the right tool. What follows is ours, organised around the OWASP API Security Top 10 but written as concrete Node practices rather than abstract categories. None of it requires exotic tooling; nearly all of it can be adopted incrementally.
Authorisation is the number one for a reason
Broken object-level authorisation tops the OWASP API list, and it is depressingly easy to write: an endpoint that loads /invoices/:id and checks only that the caller is logged in, not that the invoice is theirs. Every handler that touches a resource by ID must verify ownership or permission against the authenticated principal — and the cleanest enforcement is to scope the query itself.
// vulnerable: any authenticated user can read any invoice
const invoice = await Invoice.findById(req.params.id);
// scoped: the query cannot return another tenant's data
const invoice = await Invoice.findOne({
_id: req.params.id,
accountId: req.auth.accountId,
});
if (!invoice) return res.status(404).end();Returning 404 rather than 403 for the missing case avoids confirming that the resource exists. Apply the same scoping to updates and deletes, where the consequences are worse and the oversight just as common.
Input, injection and mass assignment
- Validate every body, param and query string against a schema (zod, JSON Schema) with unknown fields rejected — this closes mass assignment, OWASP's broken object property authorisation.
- Use parameterised queries exclusively; string-built SQL is never acceptable, including in migration scripts.
- For MongoDB, sanitise operators so a login payload of { password: { $ne: '' } } cannot become a query — schema validation that requires plain strings does this implicitly.
- Cap payload sizes at the body parser (100 KB covers most JSON APIs) and set request timeouts, addressing unrestricted resource consumption.
- Treat file uploads as hostile: validate type by content, not extension, and store outside the web root.
Dependencies are your largest attack surface
A typical Node API executes far more third-party code than first-party, and npm supply-chain attacks are no longer hypothetical. Commit your lockfile and install with npm ci so builds are reproducible. Run npm audit in CI with a failure threshold on high severity, and use Dependabot or Renovate so patching is a stream of small pull requests rather than a quarterly archaeology project. Be deliberately conservative about adding dependencies at all — every trivial package is a maintainer you now trust with production.
Secrets, transport and headers
Secrets belong in the environment or a secrets manager, never in the repository — and a leaked secret is rotated, not merely deleted from history. Terminate TLS everywhere, including service-to-service traffic inside the cluster where practical. Then spend five minutes on headers: helmet sets sensible defaults in one line, and for pure APIs the essentials are HSTS, X-Content-Type-Options and a restrictive CORS policy listing exact origins. A wildcard CORS origin with credentials enabled is a finding in every audit we have ever read.
import helmet from 'helmet';
import cors from 'cors';
app.use(helmet());
app.use(cors({
origin: ['https://app.example.com'],
credentials: true,
}));The practices that catch what checklists miss
Rate-limit authentication routes harshly, log security events — failed logins, permission denials, token reuse — as structured data you can alert on, and make sure error responses never leak stack traces or query text in production. Finally, put a date in the diary: a checklist run twice a year, an hour each time, keeps entropy from undoing all of the above.
Security is not a feature you finish; it is a property you maintain. The habits above are the maintenance schedule.
If you would like a second pair of eyes on your API before launch, STRCLI runs security-focused code reviews for Node teams.