Database audit fix

How to Restrict PostgreSQL Client Allowed Hosts

PostgreSQL decides who may connect in pg_hba.conf, and a host line whose address column reads 0.0.0.0/0, ::/0 or all accepts a connection from any address that reaches the port. Scope each one to the app server subnet, then reload.

Hiren KalariyaLast reviewed: Sep 25, 2026Check postgresql-allowed-hosts
Medium
severity
Yes
needs root or sudo
3
results it can return
6 of 6
checks in this audit

Every threshold on this page is transcribed from the database-security-least-privilege audit script that CtrlOps runs, and a build check fails if the two ever disagree. See all 6 Least-Privilege Permissions checks, or how the audit runs.

Medium severityNeeds sudo

What this check reads

The check asks the running server where its rules live with SHOW hba_file, then reads that file as root, dropping comments and blank lines with grep -vE '^[[:space:]]*(#|$)'. An awk pass counts the remaining lines whose first field starts with host, which takes in host, hostssl, hostnossl, hostgssenc and hostnogssenc, and whose fourth field is exactly 0.0.0.0/0, ::/0 or all. One matching line is the threshold: any count above zero is a WARN that quotes the number of entries, and a count of zero passes.

When it applies

Runs only when PostgreSQL is detected and reachable via PGOK=1; otherwise SKIP. Reading the HBA file itself needs root. It audits the ACL, not the listener - a wide entry is reported even when listen_addresses='localhost'. Matching is narrow and literal: field 1 must start with host and field 4 must be exactly 0.0.0.0/0, ::/0 or all. Two consequences the README also records as known gaps: the separate-netmask form (host all all 0.0.0.0 0.0.0.0 md5) is missed, and include/include_if_exists/include_dir directives (PostgreSQL 16+) are not followed. samehost and samenet are correctly not reported.

What each result means

Result thresholds this check applies
ResultWhenWhat it means
WARNAny such lineAt least one pg_hba entry accepts connections from any address, so the network no longer narrows who may attempt a login.
PASSAll host lines name specific addresses/subnetsEvery host line this parser could see names a specific address, though separate-netmask lines and included files are beyond its reach.
SKIPNot accessibleNothing was verified. The HBA file was never located or read, so the connection rules remain unknown.

Why it matters

pg_hba.conf is PostgreSQL's network ACL. An all/0.0.0.0/0 address column removes the network dimension entirely, leaving only the password (or worse, trust). OWASP: accounts connect only from allowed hosts. CIS PostgreSQL "Ensure pg_hba.conf entries are scoped".

Why it fails, and when it is wrong

  • Docker postgres image appends host all all all scram-sha-256 (and trust if POSTGRES_HOST_AUTH_METHOD=trust).
  • Separate-netmask syntax (host all all 0.0.0.0 0.0.0.0 md5) is missed: field 4 is 0.0.0.0, not 0.0.0.0/0 (false PASS).
  • samehost/samenet keywords are fine and not reported.
  • include/include_dir (PostgreSQL 16+) are not followed.
  • A hostssl ... 0.0.0.0/0 cert line (client-certificate auth) is strong despite the wide scope; the check still warns.
  • Lines are evaluated even if listen_addresses=localhost; the check audits the ACL, not the listener.

How to fix it

# pg_hba.conf
hostssl  appdb   app   10.0.0.0/24    scram-sha-256
hostssl  all     all   0.0.0.0/0      reject          # explicit catch-all

Then SELECT pg_reload_conf(); and check SELECT * FROM pg_hba_file_rules;.

Verify the fix

# The server's own parsed view - resolves includes, unlike the check:
sudo -u postgres psql -X -c \
  "SELECT line_number, type, database, user_name, address, netmask, auth_method
     FROM pg_hba_file_rules ORDER BY line_number"
# expected: no address of 0.0.0.0/0, ::/0 or 'all' except a deliberate reject catch-all

sudo -u postgres psql -X -c "SELECT * FROM pg_hba_file_rules WHERE error IS NOT NULL"
# expected: no rows

# Prove it from outside:
psql "host=<server> user=app dbname=appdb" -c 'SELECT 1'
# expected from a non-allowed address: no pg_hba.conf entry for host ...

Debugging

HAS_PG=0 or PGOK=0; see the PostgreSQL Auth Methods debugging notes.

The two known gaps. Check for the separate-netmask form with sudo grep -nE '^host' "$(sudo -u postgres psql -X -tAc 'SHOW hba_file')", and for rules pulled in by include_dir. The pg_hba_file_rules query above sees both and is the reliable answer.

Client-certificate authentication is strong even with a wide address scope, but the check only looks at the address column. Legitimate finding to accept, provided the auth method really is cert and not a password method.

Deliberate; the check audits the ACL. Tighten the entry anyway so the ACL still holds if the listener is ever widened.

pg_hba.conf needs SELECT pg_reload_conf();. The check reads the file, so it sees your edit before the server does; pg_hba_file_rules shows what the server would load, and a reload makes it live.

pg_hba.conf is first-match-wins, so the catch-all must be the last line. Check ordering with the line_number column.

Sources

How the script reads this

Next

Re-run the Least-Privilege Permissions audit after applying the fix and confirm this check moves to PASS. CtrlOps runs all 6 checks over your existing SSH connection and scores the result, so the change is visible without reading another config file.

All 6 Least-Privilege Permissions fixes
Audit your fleet

Find every one of these on every server, in one click

CtrlOps runs this audit over your existing SSH connection - no agents, no scripts to manage. $7/user/month after a 1 month free trial - no credit card required.

Windows

✓ Start instantly·✓ No credit card·✓ No sneaky autorenewals