MONGODB SECURITY CHECKLIST

MongoDB has a long, well-documented history of public exposure incidents — Shodan finds new unauthenticated MongoDBs every week. Atlas fixes most of the network exposure but introduces its own foot-guns: connection strings shared across services, IP allowlists set to 0.0.0.0/0 “to make Vercel work”, and find() calls that pass user input as the query object (NoSQL injection). The checklist below is what we look for first when we audit a MongoDB-backed app.

Treat Critical as launch-blocking. High is week-one. Medium is the cleanup once the database is in production.

How to use this checklist

Walk it once in the Atlas dashboard (or your self-hosted admin) for your production cluster, ticking items as you go. After each fix, audit a non-production cluster too — staging clusters frequently get the same exposure as production because nobody bothered to lock them down. After the whole list passes, scan the app that connects to verify no client-side leak undoes the database-side hardening.

Critical (fix before launch)

1. Enable authentication

Why it matters. A default mongod install accepts unauthenticated connections on port 27017. Without --auth, anyone who can reach the port has full database access. This is the single most common MongoDB breach pattern — Shodan finds new exposed MongoDBs every week.

How to check. For self-hosted: confirm security.authorization: enabled in mongod.conf. For Atlas: confirm cluster has at least one database user defined.

How to fix. Enable authorization, create a database user with a strong password, restart with --auth. For Atlas, this is on by default but confirm at least one user exists.

2. Block public IP access

Why it matters. A MongoDB on the public internet (port 27017 reachable from 0.0.0.0) gets scanned within hours. Combined with weak auth or the auth-not-enforced default, that’s the breach.

How to check. For self-hosted: nmap -p 27017 your-mongo-host from outside your network. Should be filtered, not open. For Atlas: Network Access. Confirm IP allowlist does not contain 0.0.0.0/0.

How to fix. For self-hosted: bind to 127.0.0.1 or a private network only; add a firewall rule. For Atlas: add only your app server IPs (or use VPC peering / private endpoints).

3. Configure RBAC with least privilege per service

Why it matters. A service connecting with the root or dbAdmin role can drop collections, create users, and read every database. Most apps need only readWrite on a specific database.

How to check. db.runCommand({ usersInfo: 1 }). List every user and the roles assigned. Cross-reference against what each service actually needs.

How to fix. Create per-service users with roles scoped to a specific database (readWrite). Avoid root, dbAdmin, userAdmin for app services. Rotate broad-role passwords.

4. Enable TLS on all connections

Why it matters. Plaintext MongoDB connections expose every query and result on the wire. On a shared network (cloud VPC, internal LAN), an attacker with packet capture reads everything.

How to check. For self-hosted: mongod.conf should have net.tls.mode: requireTLS. For Atlas: TLS is on by default; confirm clients use tls=true in the URI.

How to fix. Enable TLS in the server config. Provide certificates via your CA. Reject connections without TLS.

5. Disable JavaScript execution in queries

Why it matters. MongoDB supports server-side JavaScript via $where, $function, and mapReduce. Combined with NoSQL injection (taking user input as the query object), this becomes RCE on the database server.

How to check. db.serverStatus().security.javascriptEnabled should be false unless required. Check application code for $where and mapReduce usage.

How to fix. In mongod.conf, set security.javascriptEnabled: false. Replace $where queries with explicit operators. Refactor mapReduce to aggregation pipelines.

6. Validate input shape — never pass user input as query objects

Why it matters. NoSQL injection is the MongoDB-equivalent of SQL injection. db.users.findOne({ email: req.body.email }) looks safe — but if req.body.email is { $ne: null }, the query matches every user. AI-generated code routinely makes this mistake.

How to check. Search the codebase for queries that spread or interpolate user input into the query object: find(req.body), findOne(req.query), update(req.body, req.body).

How to fix. Validate input is the expected primitive type (string for emails, ObjectId for IDs) before using it in a query. Use Mongoose schemas or explicit type checks.

High (fix in the first week)

7. Rotate passwords for built-in admin accounts

If you imported a database from a backup or template, the built-in admin credentials may still be the defaults. Rotate them immediately.

8. Enable audit logging

For self-hosted (Enterprise): auditLog.destination: file with auditAuthorizationSuccess enabled. For Atlas: Database Auditing in the cluster settings. Ship logs to your SIEM.

9. Configure connection rate limits

Slowloris-style attacks against MongoDB are real. Configure connection limits on the load balancer or net.maxIncomingConnections to cap concurrent connections per source.

10. Pin server version

mongod versions sometimes change behavior in ways that affect security (default ciphers, default features). Pin a major.minor version and test before bumping.

11. Verify Atlas backup encryption

Atlas backups are encrypted by default but the encryption keys are managed by Atlas. For sensitive data, configure customer-managed keys (KMIP) so backups can’t be read by Atlas operators.

12. Restrict who can drop collections

Application service users should not have dropCollection privilege. Reserve it for ops tooling.

Medium (fix when you can)

13. Encrypt at rest with KMS-managed keys

For self-hosted: enable WiredTiger encryption. For Atlas: enable customer-managed keys.

14. Configure backup retention and test restores

Backups exist for a reason. Test restores quarterly to confirm they actually work.

15. Disable unused authentication mechanisms

If you only use SCRAM-SHA-256, disable SCRAM-SHA-1 and MONGODB-CR. Each enabled mechanism is attack surface.

16. Restrict change streams to authorized services

Change streams can stream every modification to a collection in real time. Restrict the role that can open them.

17. Audit installed extensions / drivers

Drivers evolve; pin versions and audit changelogs. Old drivers sometimes have CVEs that affect connection handling.

18. Set up alerting on connection-count anomalies

Sudden spikes signal an attack or a misconfigured service. Alert on outliers.

After every schema or config change

  • Re-confirm security.authorization is enabled.
  • Re-confirm IP allowlist is correct.
  • Re-test from outside your network with nmap.
  • Re-run a query that should fail (no auth, wrong role) to confirm rejection.

Common attack patterns we see in MongoDB apps

The exposed mongod. mongod running on a cloud VM with port 27017 open and --auth not set. Database is on Shodan within hours; ransom note appears in info collection within days.

The 0.0.0.0/0 Atlas allowlist. Atlas IP allowlist set to 0.0.0.0/0 because “Vercel’s IPs change too often”. Anyone with the connection string from anywhere can connect.

The $where injection. App takes user input into a find({ $where: ... }) query. Attacker passes '1==1; while(1){}', takes the database offline.

The { $ne: null } auth bypass. Login query is findOne({ username, password }). Attacker submits {"username": "admin", "password": {"$ne": null}} and matches the admin record without knowing the password.

How to Secure MongoDB

Step-by-step guide for hardening a MongoDB deployment — auth setup, network restrictions, RBAC patterns, and the NoSQL injection prevention above in long form.

Is MongoDB Safe?

In-depth analysis of MongoDB’s defaults — what’s locked down, what isn’t, and what we find when we audit a typical MongoDB-backed app.

Automate Your Checklist

A checklist tells you what to look for. A scanner tells you what’s actually broken in the deployed app that connects to your database. VibeEval scans the app, attempts NoSQL injection and auth-bypass vectors, and reports what got through.

SCAN YOUR APP

14-day trial. No card. Results in under 60 seconds.

START FREE SCAN