PST-062: The whole .env, including the secret keys, is handed to the PostgreSQL container #791

Closed
opened 2026-10-10 10:56:33 +00:00 by tiagoagueda · 0 comments
Owner

Found in the security audit of 2026-10-10 (SECURITY-AUDIT-2026-10-10.md), run against main at c30851b from 8 to 10 October 2026, as PST-062. Severity: Low.

The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it.


  • Severity: Low
  • Category: secrets exposure / deployment
  • Location: docker/compose.postgres.yml (117-125)
  • Found by: configuration and dependencies

Who can do it, and what they need. Anyone who gains code execution inside the db container (a PostgreSQL vulnerability or a mis-set superuser role with COPY TO PROGRAM), or who can read that container's environment via the Docker API. Precondition: PostgreSQL deployment profile and such a compromise.

How it works.

  1. The db service uses env_file: ../.env, so every Postulo variable (POSTULO_SECRET_KEY, POSTULO_FIELD_KEY, POSTULO_EMAIL_HOST_PASSWORD, OIDC client secret, metrics/logs tokens) is in the postgres process environment.
  2. From inside that container /proc/1/environ reveals them; from the host docker inspect postulo-db-1 prints them.
  3. With SECRET_KEY/FIELD_KEY the attacker decrypts every stored connection credential and OAuth refresh token in the database it already holds, and can forge session cookies and password-reset tokens for the web container.

Impact. Turns a database-tier compromise (which yields hashed passwords and encrypted secrets) into one that also yields the key that decrypts those secrets, defeating the threat model's "key held outside the database" argument for that profile. The comment says the db only needs POSTGRES_PASSWORD.

Evidence.

compose.postgres.yml:118-125 `db: image: postgres:17-alpine ... env_file: - ../.env  environment: POSTGRES_DB: postulo  POSTGRES_USER: postulo`; the file header at lines 9-12 says the db container reads only POSTGRES_PASSWORD from it.

Verification (verdict: confirmed; severity after verification: Low). Keep it low. Location: docker/compose.postgres.yml:121-122 (db.env_file). Attacker: code execution as the postgres user in the db container (PostgreSQL vulnerability, or a superuser role used through SQL), not Docker API access. Gain: POSTULO_SECRET_KEY and POSTULO_FIELD_KEY (decrypting stored connection secrets and OAuth refresh tokens) and the env-only SMTP and OIDC credentials. Drop the 'forge session cookies' claim (sessions are DB-backed with random keys). The password-reset forgery is redundant with DB write access. Remediation: give the db container only POSTGRES_PASSWORD, with a separate small env file (for example docker/db.env, or POSTGRES_PASSWORD_FILE plus a Compose secret), keep the full .env for the Postulo services, and update the #582 test. Optionally create a non-superuser application role.

Suggested remediation. Give the db service only POSTGRES_PASSWORD (a dedicated env file, or environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} with the compose project's env file pointed at the repository root via --env-file), and document the split in .env.example.

Found in the security audit of 2026-10-10 (`SECURITY-AUDIT-2026-10-10.md`), run against `main` at `c30851b` from 8 to 10 October 2026, as **PST-062**. Severity: **Low**. The text below is the audit's entry, unchanged apart from links to the other issues it names. The finding was produced by automated review and checked by a second automated pass; re-check it before acting on it. --- - **Severity:** Low - **Category:** secrets exposure / deployment - **Location:** `docker/compose.postgres.yml` (117-125) - **Found by:** configuration and dependencies **Who can do it, and what they need.** Anyone who gains code execution inside the db container (a PostgreSQL vulnerability or a mis-set superuser role with COPY TO PROGRAM), or who can read that container's environment via the Docker API. Precondition: PostgreSQL deployment profile and such a compromise. **How it works.** 1. The db service uses `env_file: ../.env`, so every Postulo variable (POSTULO_SECRET_KEY, POSTULO_FIELD_KEY, POSTULO_EMAIL_HOST_PASSWORD, OIDC client secret, metrics/logs tokens) is in the postgres process environment. 2. From inside that container /proc/1/environ reveals them; from the host `docker inspect postulo-db-1` prints them. 3. With SECRET_KEY/FIELD_KEY the attacker decrypts every stored connection credential and OAuth refresh token in the database it already holds, and can forge session cookies and password-reset tokens for the web container. **Impact.** Turns a database-tier compromise (which yields hashed passwords and encrypted secrets) into one that also yields the key that decrypts those secrets, defeating the threat model's "key held outside the database" argument for that profile. The comment says the db only needs POSTGRES_PASSWORD. **Evidence.** ```text compose.postgres.yml:118-125 `db: image: postgres:17-alpine ... env_file: - ../.env environment: POSTGRES_DB: postulo POSTGRES_USER: postulo`; the file header at lines 9-12 says the db container reads only POSTGRES_PASSWORD from it. ``` **Verification** (verdict: confirmed; severity after verification: Low). Keep it low. Location: docker/compose.postgres.yml:121-122 (db.env_file). Attacker: code execution as the postgres user in the db container (PostgreSQL vulnerability, or a superuser role used through SQL), not Docker API access. Gain: POSTULO_SECRET_KEY and POSTULO_FIELD_KEY (decrypting stored connection secrets and OAuth refresh tokens) and the env-only SMTP and OIDC credentials. Drop the 'forge session cookies' claim (sessions are DB-backed with random keys). The password-reset forgery is redundant with DB write access. Remediation: give the db container only POSTGRES_PASSWORD, with a separate small env file (for example docker/db.env, or `POSTGRES_PASSWORD_FILE` plus a Compose secret), keep the full .env for the Postulo services, and update the #582 test. Optionally create a non-superuser application role. **Suggested remediation.** Give the db service only POSTGRES_PASSWORD (a dedicated env file, or `environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}` with the compose project's env file pointed at the repository root via --env-file), and document the split in .env.example.
tiagoagueda added this to the 0.6.0 milestone 2026-10-10 10:58:01 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#791
No description provided.