Skip to content

Enable MongoDB authorization

Severity: criticalApplies to: MongoDB 6.x / 7.x / 8.x
The fix/etc/mongod.conf
security:
authorization: enabled
Terminal window
sudo systemctl restart mongod

Do not do this yet. Read the safety section first — the order matters, and doing this on a running system breaks every client at once.

Every other database on this site ships with some authentication. MongoDB ships with none. A default mongod is not protected by a weak password; there is no password. Connect, and you are effectively an administrator: read every collection, drop every database, create users.

The only thing standing between a default MongoDB and the internet is bindIp, which has defaulted to loopback since 3.6. That default is the reason the situation improved after 2017 — but it is one line in one file, and a container image, a cloud template or a colleague debugging a connection can undo it in a second. When it goes, there is nothing behind it.

That combination — no authentication, and one setting away from public — is what produced the ransomware wave.

MongoDB has a bootstrap mechanism that looks like a hole and isn’t:

When authorization is enabled and no users exist yet, MongoDB permits unauthenticated connections from localhost — but only to create the first user in the admin database. As soon as one user exists, the exception closes permanently and automatically.

This is what lets you enable auth and then create your admin account, rather than needing a credential that doesn’t exist yet. It’s a well-designed bootstrap, and it is not something to disable.

Two things to know about it:

  • It is localhost only. It never applies over the network, so it is not a remote hole.
  • It closes on the first user in admin, not the first user anywhere. Create your admin user first, then everything else.
use admin
db.createUser({
user: "admin",
pwd: passwordPrompt(),
roles: [
{ role: "userAdminAnyDatabase", db: "admin" },
{ role: "readWriteAnyDatabase", db: "admin" }
]
})

Use passwordPrompt(), not a string literal. A password typed into mongosh as a literal lands in ~/.mongosh/mongosh_repl_history and in your shell history if you passed --eval. passwordPrompt() reads it interactively and keeps it out of both.

Note this first account is deliberately an admin account, not your application account — see least privilege roles for the accounts your apps should get.