Skip to content

PostgreSQL exposed to the internet

Severity: criticalApplies to: Any reachable cluster

A PostgreSQL cluster reachable from an untrusted network is a different risk from an open Redis. Postgres does authenticate by default, so an exposed cluster is not automatically compromised — it is automatically under attack, and the outcome depends entirely on what pg_hba.conf says.

The two failure modes are worth separating, because they need different reactions.

If any rule uses trust with an address an attacker can reach, there is no attack to speak of. They connect as postgres and it is over. No guessing, no exploit — the configuration invited them.

This is rare on the public internet and common on “internal” networks that turn out to be less internal than assumed: a VPC shared with another tenant, a container network, a VPN with wide membership.

With scram-sha-256 and a wide host all all 0.0.0.0/0 rule, what you have is a brute-force target. Postgres has no built-in rate limiting and no account lockout — it will answer authentication attempts as fast as they arrive, forever. Weak passwords fall; strong ones don’t.

Both modes matter more than “someone reads the database”, because a superuser connection is not confined to the database:

  • COPY ... FROM PROGRAM 'command' executes a shell command as the postgres OS user. That is a shell, reached over port 5432.
  • pg_read_file() / pg_read_binary_file() read files from the host filesystem.
  • CREATE EXTENSION or an untrusted PL can load code.
  • Superuser bypasses every permission check, including row-level security.

So “we don’t keep anything sensitive in that database” is the same mistake as with Redis. The data is not the prize; the host is. And it is why not connecting as superuser matters even inside a trusted network — it decides whether an injection is a data problem or a host problem.

  1. Remove trust — nothing else matters while it is there.
  2. Scope pg_hba.conf — replace 0.0.0.0/0 with the addresses that actually connect. This is the control that closes it.
  3. Firewall 5432 — same reasoning as everywhere else: an unreachable daemon needs no password.
  4. Stop connecting as superuser — bounds the damage of everything above going wrong.

Steps 1 and 2 are a pg_hba.conf edit and a reload. No restart, no downtime for established connections.