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
- PostgreSQL image, fallback credentials, and host-port mapping:
|
postgres: |
|
image: postgres:13-alpine |
|
restart: unless-stopped # Restart on crash (or on exit with non-zero code) |
|
environment: |
|
POSTGRES_USER: ${DB_USER:-myuser} |
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-mypassword} |
|
POSTGRES_DB: ${DB_NAME:-mydatabase} |
|
ports: |
|
- "5431:5432" |
|
networks: |
|
- backend |
|
volumes: |
|
- pgdata:/var/lib/postgresql/data |
|
healthcheck: |
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-myuser} -d ${DB_NAME:-mydatabase}"] |
- The orchestrator already uses the private service name and container port:
|
orchestrator: |
|
image: randao/orchestrator:latest |
|
restart: unless-stopped # Restart on crash (or on exit with non-zero code) |
|
depends_on: |
|
postgres: |
|
condition: service_healthy |
|
environment: |
|
DB_HOST: postgres |
|
DB_PORT: 5432 |
|
DB_USER: ${DB_USER:-myuser} |
|
DB_PASSWORD: ${DB_PASSWORD:-mypassword} |
|
DB_NAME: ${DB_NAME:-mydatabase} |
- Application-side credential fallbacks:
|
export const dbConfig = { |
|
host: process.env.DB_HOST || 'localhost', |
|
port: parseInt(process.env.DB_PORT || '5432', 10), |
|
user: process.env.DB_USER || 'myuser', |
|
password: process.env.DB_PASSWORD || 'mypassword', |
|
database: process.env.DB_NAME || 'mydatabase', |
.env.example omits the actual DB_* variables: https://github.com/RandAOLabs/Randomness-Provider/blob/d38095b99a05b7b03fefc3da02d2f9be87c5aaf5/docker-compose/.env.example
- Docker Compose port publishing behavior: https://docs.docker.com/reference/compose-file/services/#ports
- Official PostgreSQL image initialization behavior: https://github.com/docker-library/docs/blob/master/postgres/README.md#postgres_user
- PostgreSQL version support policy: https://www.postgresql.org/support/versioning/
Proposed fix
- Remove
ports: - "5431:5432" from the base Compose file. Container-to-container access through postgres:5432 on backend will continue to work.
- 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.
- 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.
- Add the exact
DB_* names to .env.example, but do not include a usable sample password. Document how to generate a cryptographically random password.
- 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.
- 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.
Summary
The default Docker Compose deployment combines several unsafe PostgreSQL defaults:
5431:5432is published without a host IP, so Docker binds PostgreSQL to all host interfaces by default.POSTGRES_USERis passed to the application. In the official PostgreSQL image, that user is created with superuser privileges.postgres:13-alpine; PostgreSQL 13 reached end of life on November 13, 2025.This is easy to deploy unintentionally because
.env.exampledoes not define the actualDB_*variables, while the setup documentation refers to differently named database variables.The orchestrator already connects to
postgres:5432over the privatebackendDocker 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
Randomness-Provider/docker-compose/docker-compose.yml
Lines 2 to 16 in d38095b
Randomness-Provider/docker-compose/docker-compose.yml
Lines 26 to 37 in d38095b
Randomness-Provider/orchestrator/src/db_tools.ts
Lines 5 to 10 in d38095b
.env.exampleomits the actualDB_*variables: https://github.com/RandAOLabs/Randomness-Provider/blob/d38095b99a05b7b03fefc3da02d2f9be87c5aaf5/docker-compose/.env.exampleProposed fix
ports: - "5431:5432"from the base Compose file. Container-to-container access throughpostgres:5432onbackendwill continue to work.127.0.0.1:5431:5432. Documentdocker compose exec postgres psql ...as the preferred administrative path.${DB_PASSWORD:?DB_PASSWORD must be set}, and fail fast if they are absent.DB_*names to.env.example, but do not include a usable sample password. Document how to generate a cryptographically random password.NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATIONand only the schema/table privileges required by the orchestrator.Existing-installation notes
pgdatavolume.POSTGRES_*environment variables does not rotate roles in an already initialized volume; existing credentials must be changed with SQL and grants/ownership migrated.pg_dump/restore orpg_upgradeworkflow; changing only the image tag is not sufficient.Acceptance criteria
docker compose uppublishes no PostgreSQL port on the host.postgres:5432onbackend.