MongoDB Service Without Authentication Detection (Nessus plugin 81777) means a scanner reached a MongoDB server, usually on TCP 27017, and ran database commands without logging in. To enable MongoDB authentication, create an admin user over localhost, set security.authorization: enabled in mongod.conf and restart mongod, then bind net.bindIp to 127.0.0.1 or a private address and firewall port 27017.
What the scanner is actually detecting
The finding comes from Tenable Nessus plugin 81777, titled MongoDB Service Without Authentication Detection. It is a remote, unauthenticated network check. Tenable’s description says MongoDB is listening on the remote port and is configured to allow connections without any authentication, and its solution is to enable authentication or restrict access to the service.
| Field | Value on the Tenable plugin page |
|---|---|
| Plugin name | MongoDB Service Without Authentication Detection |
| Plugin ID | 81777 (mongodb_authentication_disabled.nasl) |
| Severity | Critical (CVSS v3 9.8) |
| Type and family | Remote, Databases |
| Exploited by Nessus | Yes |
Two MongoDB defaults explain how a host ends up here. security.authorization defaults to disabled, so a fresh install accepts every client that can connect. Since MongoDB 3.6, net.bindIp defaults to localhost, so a remote scanner only gets in when someone widened the binding (bindIp: 0.0.0.0, bindIpAll: true or –bind_ip_all) without turning on access control. The official mongo Docker image does exactly that: its entrypoint adds –bind_ip_all, and it only adds –auth when you supply a root username and password.
Tenable also notes that the opcode Nessus uses to test the instance has been deprecated since MongoDB 5.0. Treat the plugin as a strong signal, and confirm by hand on newer versions.
Real-world risk
Without access control, every client that can reach the port has full rights. In practice that means an attacker can:
- Read every database. Customer records, sessions, API tokens and anything else the application stores.
- Change or delete data. Internet-exposed MongoDB servers without authentication have repeatedly been hit by automated campaigns that copy or drop databases and leave a ransom note behind.
- Administer the server. Create users, change runtime settings or shut mongod down.
The finding does not by itself give an attacker a shell on the operating system; the damage is to data and availability. Urgency depends on who can reach port 27017. An Internet-facing instance should be fixed today, and it is worth reviewing your external attack surface management scope to learn how it got there. An instance reachable only from its application servers is lower risk, but any compromised host on that segment gets full access.
How to confirm it on the host
From another machine, ideally the scanner’s network segment:
mongosh "mongodb://<host>:27017/" --quiet --eval 'db.adminCommand({ listDatabases: 1, nameOnly: true })'
# a list of databases = no authentication, the finding is valid
# Unauthorized ... requires authentication = access control is on
nmap -p 27017 --script mongodb-databases <host>
On a Linux host (package installs use /etc/mongod.conf and the mongod service):
sudo ss -tlnp 'sport = :27017'
grep -nE 'bindIp|bindIpAll|authorization' /etc/mongod.conf
ps -o args= -C mongod
mongosh --quiet --eval 'db.adminCommand({ getCmdLineOpts: 1 }).parsed'
getCmdLineOpts shows the options the running process actually uses, including the config file path. A listener on 0.0.0.0 with no security section in the parsed output confirms the finding. Also check the ps output for –bind_ip_all, which overrides the file.
On Windows (MSI installs use the MongoDB service and <install directory>binmongod.cfg):
Get-NetTCPConnection -LocalPort 27017 -State Listen | Select-Object LocalAddress, OwningProcess
(Get-CimInstance Win32_Service -Filter "Name='MongoDB'").PathName
Select-String -Path "C:Program FilesMongoDBServer*binmongod.cfg" -Pattern "bindIp|authorization"
How to fix it
Step 1: create the first administrator over localhost
Run this on the database host itself. If authorization is still off, it simply works; if you already enabled it, the localhost exception lets a local connection create the first user, then closes.
mongosh --port 27017
use admin
db.createUser({
user: "admin",
pwd: passwordPrompt(),
roles: [ { role: "root", db: "admin" } ]
})
MongoDB’s tutorial uses userAdminAnyDatabase plus readWriteAnyDatabase instead of root; its documentation notes that userAdminAnyDatabase is effectively a superuser anyway. What matters is that the first user can create other users.
Step 2: create application users
Give each application its own user with only the roles it needs, before you turn authorization on:
use appdb
db.createUser({
user: "appuser",
pwd: passwordPrompt(),
roles: [ { role: "readWrite", db: "appdb" } ]
})
Monitoring agents usually need the clusterMonitor role, and backup jobs need backup and restore.
Step 3: enable authorization and restrict bindIp on Linux
Back up the file first (sudo cp -p /etc/mongod.conf /etc/mongod.conf.bak), then set these sections. In the default package file the security: line is commented out; uncomment it rather than adding a second one, and indent with spaces, not tabs.
net:
port: 27017
bindIp: 127.0.0.1,10.0.5.20
security:
authorization: enabled
Replace 10.0.5.20 with the private address that application servers connect to, or keep only 127.0.0.1 if every client is local. bindIp lists the local interfaces mongod listens on; it is not a list of allowed clients, which is why the firewall step still matters. Remove any bindIpAll line, since the two settings are mutually exclusive. Then restart:
sudo systemctl restart mongod
sudo systemctl status mongod
sudo tail -n 50 /var/log/mongodb/mongod.log
Windows service
Edit C:Program FilesMongoDBServer<version>binmongod.cfg (or the path shown by the service’s PathName) with the same net and security sections, then restart the service from an elevated prompt:
net stop MongoDB
net start MongoDB
Docker containers
For a new container, supply both root variables so the entrypoint creates a root user and starts mongod with –auth. The _FILE variant reads the password from a file. Publish the port on loopback only, or not at all if clients are containers on the same Docker network.
docker run -d --name mongo -p 127.0.0.1:27017:27017
-v mongo-data:/data/db
-v /srv/mongo/root_pw:/run/secrets/mongo_root_pw:ro
-e MONGO_INITDB_ROOT_USERNAME=admin
-e MONGO_INITDB_ROOT_PASSWORD_FILE=/run/secrets/mongo_root_pw
mongo
These variables are ignored when the data directory already contains a database. For an existing container, create the admin user from inside it with docker exec -it mongo mongosh (that is a localhost connection), then recreate the container with –auth after the image name; the entrypoint passes extra arguments to mongod.
Replica sets and sharded clusters
Setting security.authorization on one member at a time is not the documented procedure. Members also need internal authentication, and setting security.keyFile enforces both member authentication and client access control. Generate a key with openssl rand -base64 756, chmod 400 it, copy it to every member, and follow MongoDB’s “Update Self-Managed Replica Set to Keyfile Authentication” tutorial, which needs downtime, or its no-downtime variant. In sharded clusters, create a user administrator on each shard as well, or disable the localhost exception with setParameter: enableLocalhostAuthBypass: false.
Firewall TCP 27017
Allow the port only from application servers. With firewalld (also remove any earlier –add-port=27017/tcp rule):
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.5.0/24" port port="27017" protocol="tcp" accept'
sudo firewall-cmd --reload
With ufw, add the allow rule before the deny:
sudo ufw allow from 10.0.5.0/24 to any port 27017 proto tcp
sudo ufw deny 27017/tcp
On Windows, add a scoped rule and disable any broad “allow mongod.exe” rule created at first launch, because a wider allow rule still admits everyone:
New-NetFirewallRule -DisplayName "MongoDB 27017 app subnet" -Direction Inbound -Protocol TCP -LocalPort 27017 -RemoteAddress 10.0.5.0/24 -Action Allow
Get-NetFirewallRule -Direction Inbound -Enabled True | Where-Object { ($_ | Get-NetFirewallApplicationFilter).Program -like '*mongod.exe' }
Docker notes that published container ports bypass ufw, so for containers rely on the port binding above.
How to verify the fix and rescan
- From a remote machine, the listDatabases command above should now fail with an Unauthorized error, or time out if the firewall blocks that source.
- With credentials it should succeed: mongosh “mongodb://<host>:27017/” –authenticationDatabase admin -u admin -p (an empty -p makes mongosh prompt for the password).
- On the host, db.adminCommand({ getCmdLineOpts: 1 }).parsed.security should show authorization: ‘enabled’ or a keyFile.
- nmap –script mongodb-databases should no longer list databases.
- Check application, worker and backup logs for authentication errors, then rescan with the same Nessus policy and scanner. Plugin 81777 should no longer be reported. Because of Tenable’s opcode note, keep the manual check in your evidence for MongoDB 5.0 and later.
What can break and how to roll back
- Clients without credentials fail with errors saying the command requires authentication: applications, workers, cron jobs, BI tools and monitoring exporters.
- Backups. mongodump and mongorestore now need –username, –password and –authenticationDatabase admin, or a –uri with credentials.
- Connection strings. Passwords containing $ : / ? # [ ] @ must be percent-encoded, and clients whose user lives in admin need authSource=admin.
- Startup failures. A YAML indentation error, or a bindIp address the host does not have, stops mongod from starting. Read mongod.log first.
- Replication. Members changed piecemeal without a shared keyfile can stop replicating.
To roll back a standalone server, restore the backup and restart: sudo cp -p /etc/mongod.conf.bak /etc/mongod.conf && sudo systemctl restart mongod. The users you created remain and are harmless. Keep the bindIp and firewall restrictions while you fix the clients, and treat the rollback as temporary.
Common false positive reasons
Nessus proves access by running a command, so true false positives are rare. When the finding looks wrong, check these:
- A different instance answered. A second mongod on another port (shard members default to 27018, config servers to 27019), a test container, or a NAT rule forwarding 27017 elsewhere. Match the port and address in the plugin output.
- The running process uses a different config. You edited one file, but getCmdLineOpts or the Windows service PathName points to another, a command-line flag overrides it, or mongod was never restarted.
- The container came back unprotected. It was recreated from the stock image without the root variables. That is a real finding, not a false positive.
- The scan predates the change. The old result stays in the report until the same scanner rescans the host.
FAQ
Is binding MongoDB to 127.0.0.1 enough to close the finding?
It removes the path the scanner used, so the plugin stops firing, but any local process can still read everything. MongoDB advises enabling authentication before binding to any non-localhost address. Do both.
Should the first user get root or userAdminAnyDatabase?
Either works. Keep that account for administration only and give applications separate users with database-scoped roles such as readWrite.
Does enabling authentication encrypt traffic?
No. SCRAM protects the login exchange, but queries and results still cross the network in cleartext unless you also configure TLS in the net.tls section.
Do I need downtime?
A standalone server needs one restart. A replica set needs either a short full outage or MongoDB’s no-downtime rolling procedure for keyfile authentication.
Tracking this finding across many hosts
Open MongoDB instances tend to reappear as containers are recreated and test databases are spun up. A platform such as SITEY can import Nessus results (as an uploaded .nessus export) alongside other scanners, draft a host-specific remediation script that its Windows or Linux agent deploys only after human approval, and re-test each Nessus finding to confirm plugin 81777 has closed.
Sources
- Tenable: MongoDB Service Without Authentication Detection (plugin 81777)
- MongoDB documentation: Use SCRAM to Authenticate Clients on Self-Managed Deployments
- MongoDB documentation: Localhost Exception in Self-Managed Deployments
- MongoDB documentation: Update Self-Managed Replica Set to Keyfile Authentication
- Docker Hub: official mongo image