Skip to content

[Security] Make PostgreSQL private by default and remove fallback superuser credentials #13

Description

@zigengZ

Summary

The default Docker Compose deployment combines several unsafe PostgreSQL defaults:

  • 5431:5432 is published without a host IP, so Docker binds PostgreSQL to all host interfaces by default.
  • Compose and the orchestrator silently fall back to static database credentials.
  • The same POSTGRES_USER is passed to the application. In the official PostgreSQL image, that user is created with superuser privileges.
  • The deployment uses postgres:13-alpine; PostgreSQL 13 reached end of life on November 13, 2025.

This is easy to deploy unintentionally because .env.example does not define the actual DB_* variables, while the setup documentation refers to differently named database variables.

The orchestrator already connects to postgres:5432 over the private backend Docker network, so publishing the database on the host is not required for normal operation. The database stores sensitive time-lock-puzzle and provider state, making unintended access a confidentiality and protocol-integrity risk.

Evidence in the current default branch

Proposed fix

  1. Remove ports: - "5431:5432" from the base Compose file. Container-to-container access through postgres:5432 on backend will continue to work.
  2. If host-side access is useful for development, provide an explicit opt-in override bound only to loopback, for example 127.0.0.1:5431:5432. Document docker compose exec postgres psql ... as the preferred administrative path.
  3. Remove credential fallbacks from both Compose and the application. Require the exact variables with fail-closed interpolation, for example ${DB_PASSWORD:?DB_PASSWORD must be set}, and fail fast if they are absent.
  4. Add the exact DB_* names to .env.example, but do not include a usable sample password. Document how to generate a cryptographically random password.
  5. Separate bootstrap/admin credentials from runtime credentials. Create a dedicated application role with NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION and only the schema/table privileges required by the orchestrator.
  6. Upgrade to a supported PostgreSQL major version and pin an intentional image version or digest.

Existing-installation notes

  • Removing the host port is safe for the existing pgdata volume.
  • Changing POSTGRES_* environment variables does not rotate roles in an already initialized volume; existing credentials must be changed with SQL and grants/ownership migrated.
  • A PostgreSQL major-version upgrade requires a tested pg_dump/restore or pg_upgrade workflow; changing only the image tag is not sufficient.

Acceptance criteria

  • A default docker compose up publishes no PostgreSQL port on the host.
  • Startup fails clearly when required database secrets are missing; no usable fallback password remains in source or examples.
  • The orchestrator continues its normal database operations over postgres:5432 on backend.
  • The runtime application role is not a superuser and cannot create databases, roles, or replication slots.
  • Documentation covers credential rotation, major-version migration, backup/rollback, and loopback-only opt-in access.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions