Exposed data stores
critical external
What it inspects
Opens a plain TCP connection to each of these ports on the scanned host and records whether it connects: 6379 (Redis), 5432 (PostgreSQL), 3306 (MySQL/MariaDB), 27017 (MongoDB), 9200 (Elasticsearch), 11211 (Memcached), 9000 (ClickHouse), 5984 (CouchDB). It sends nothing, never logs in and reads no data. Any port that connects is a FAIL. This is an active check: it runs only after you have verified ownership of the host, and only against that host.
Why it matters
Data stores are built to trust the network around them. Many have no password by default, or accept connections from anywhere once bound to a public address. Automated scanners find open Redis, MongoDB and Elasticsearch servers within hours, and the usual outcome is stolen data, a wiped database with a ransom note, or a foothold on the machine. Only your own application needs to talk to the store, so there is rarely a reason for the internet to.
How to verify
# only against hosts you own
nmap -Pn -p 6379,5432,3306,27017,9200,11211,9000,5984 example.com
# Every port should be reported closed or filtered. On the server itself, an address of 0.0.0.0, * or [::] means every interface:
ss -tln | grep -E ':(6379|5432|3306|27017|9200|11211|9000|5984)[[:space:]]'
How to fix
Bind each data store to 127.0.0.1 (or a private address), publish container ports to loopback only, and block the ports at the host firewall as a second layer.
Bind each data store to loopback or a private address needs your judgement
Any distro
# Decide, per data store, who really needs to reach it. Almost always the answer is "only the
# application on this same machine", which means loopback (127.0.0.1). If the application runs on
# another machine, bind to this host's PRIVATE network address instead (never 0.0.0.0) and let only
# that machine in at the firewall, or reach the store through an SSH tunnel or VPN.
#
# First see what is listening and on which address (0.0.0.0, * or [::] mean every interface):
# ss -tlnp '( sport = :6379 or sport = :5432 or sport = :3306 or sport = :27017 or sport = :9200 or sport = :11211 or sport = :9000 or sport = :5984 )'
#
# For each store that is listening publicly: back up its config file, change ONE setting, restart,
# then run the checks at the bottom. A restart drops open connections, so pick a quiet moment.
# Paths and service names vary by distro and version; the lines below are the usual ones.
#
# Redis, /etc/redis/redis.conf (service: redis-server on Debian/Ubuntu, redis on RHEL family):
# bind 127.0.0.1 ::1
# protected-mode yes
# (use just `bind 127.0.0.1` if IPv6 is off on this host: Redis refuses to start when it cannot bind an address in the list.
# The optional form `bind 127.0.0.1 -::1` needs Redis 6.2 or newer; Debian 11 / Ubuntu 22.04 ship 6.0 and Ubuntu 20.04 ships 5.0, where it breaks startup)
#
# PostgreSQL, postgresql.conf (find it: sudo -u postgres psql -Atc 'SHOW config_file'):
# listen_addresses = 'localhost'
# Changing listen_addresses needs a restart, not a reload (service: postgresql, or postgresql-<version> on RHEL family).
#
# MySQL / MariaDB, the [mysqld] section of the server config (Debian: /etc/mysql/mysql.conf.d/mysqld.cnf or
# /etc/mysql/mariadb.conf.d/50-server.cnf; RHEL family: a file under /etc/my.cnf.d/):
# bind-address = 127.0.0.1
# (service: mysql, mariadb or mysqld depending on the distro; "skip-networking" turns TCP off completely if only the local socket is used)
#
# MongoDB, /etc/mongod.conf (service: mongod):
# net:
# bindIp: 127.0.0.1
#
# Elasticsearch, /etc/elasticsearch/elasticsearch.yml (service: elasticsearch):
# network.host: 127.0.0.1
# A multi-node cluster needs a private address here, not loopback, and transport security between nodes.
#
# Memcached (service: memcached): Debian/Ubuntu /etc/memcached.conf, add or edit the line:
# -l 127.0.0.1
# RHEL family /etc/sysconfig/memcached:
# OPTIONS="-l 127.0.0.1"
# Memcached also speaks UDP; add -U 0 to switch UDP off if you do not use it.
#
# ClickHouse (service: clickhouse-server): a file such as /etc/clickhouse-server/config.d/listen.xml containing
# <clickhouse><listen_host>127.0.0.1</listen_host></clickhouse>
# Port 9000 is also used by other software (MinIO, PHP-FPM, ...). This check only sees that something answers there.
#
# CouchDB (service: couchdb): a local .ini file (for example /opt/couchdb/etc/local.d/ or /etc/couchdb/local.ini):
# [chttpd]
# bind_address = 127.0.0.1
#
# After restarting, confirm on the server that the store now shows 127.0.0.1 (or your private address), not 0.0.0.0, *, or [::]:
# ss -tlnp '( sport = :6379 )'
# and from outside (only against hosts you own) that the port is closed or filtered:
# nmap -Pn -p 6379 example.com
# If the store used to be reachable remotely on purpose, every client that connects from another machine will now fail:
# fix those clients (private address, tunnel, VPN) before you restart.
- Publish container ports to loopback only
- Block the ports at the firewall as a second layer
2 more steps in the Fix Pack. See pricing