fix(dev): bind dev Postgres to loopback and reject public LAN IP #399

Merged
nrupard merged 2 commits from fix/dev-db-loopback-bind-on-main into main 2026-06-29 21:26:35 +02:00
Owner

Re-applies the security hunks from the stale #398 onto current main. PR #398 no longer merged (mergeable: false): its third hunk (dropping the server -> infisical depends_on) already landed separately on main when Infisical moved behind the infisical compose profile, and its branch was based on a long-superseded main. Main is still vulnerable on the two security hunks until this lands.

The dev stack discovered the host br0 IPv4 in just dev and published ports to it. On some hosts br0 carries a public address, so postgres:postgres was exposed to the internet and compromised by the PG_MEM/"wog" Postgres botnet (rogue superuser plus RCE via a SQL system() function that downloaded a miner). This hardens the dev stack so a database can never be published off-box.

compose.dev.yml now hardcodes the Postgres host publish to 127.0.0.1 (never ${MOKOSH_HOST_BIND_IP}). The database is reached in-network as postgres:5432; only host-side sqlx-cli uses the loopback port, so nothing external is lost.

justfile bind-IP discovery now keeps only RFC1918 (private) addresses (10/8, 172.16-31/12, 192.168/16) and falls back to 127.0.0.1 with a warning when the only candidate is public, so app ports are never published on a public interface.

Verification: docker compose -f compose.dev.yml config validates and renders the Postgres publish as host_ip: 127.0.0.1 (127.0.0.1:5433->5432); just --list parses the justfile; the RFC1918 filter was unit-tested against public, link-local, and the 172.15/172.32 boundary addresses; the local just pre-commit hook passed on commit.

Supersedes #398, which should be closed.

🤖 Generated with Claude Code

Re-applies the security hunks from the stale #398 onto current `main`. PR #398 no longer merged (`mergeable: false`): its third hunk (dropping the `server` -> `infisical` `depends_on`) already landed separately on main when Infisical moved behind the `infisical` compose profile, and its branch was based on a long-superseded `main`. Main is still vulnerable on the two security hunks until this lands. The dev stack discovered the host br0 IPv4 in `just dev` and published ports to it. On some hosts br0 carries a public address, so `postgres:postgres` was exposed to the internet and compromised by the PG_MEM/"wog" Postgres botnet (rogue superuser plus RCE via a SQL `system()` function that downloaded a miner). This hardens the dev stack so a database can never be published off-box. `compose.dev.yml` now hardcodes the Postgres host publish to `127.0.0.1` (never `${MOKOSH_HOST_BIND_IP}`). The database is reached in-network as `postgres:5432`; only host-side sqlx-cli uses the loopback port, so nothing external is lost. `justfile` bind-IP discovery now keeps only RFC1918 (private) addresses (`10/8`, `172.16-31/12`, `192.168/16`) and falls back to `127.0.0.1` with a warning when the only candidate is public, so app ports are never published on a public interface. Verification: `docker compose -f compose.dev.yml config` validates and renders the Postgres publish as `host_ip: 127.0.0.1` (`127.0.0.1:5433->5432`); `just --list` parses the justfile; the RFC1918 filter was unit-tested against public, link-local, and the 172.15/172.32 boundary addresses; the local `just pre-commit` hook passed on commit. Supersedes #398, which should be closed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(dev): bind dev Postgres to loopback and reject public LAN IP
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 2m23s
Check / fmt + clippy + build + tests (pull_request) Successful in 3m18s
Integration / integration tests (pull_request) Successful in 11m22s
071b3dd4bc
compose.dev.yml now hardcodes the Postgres host publish to 127.0.0.1 instead of ${MOKOSH_HOST_BIND_IP}. The database is reached in-network as postgres:5432; only host-side sqlx-cli uses the loopback port, so nothing external is lost. A prior LAN-IP bind put postgres:postgres on a public interface where it was compromised by the PG_MEM/"wog" botnet (rogue superuser plus RCE via a SQL system() function that downloaded a miner).

justfile bind-IP discovery in `just dev` now keeps only RFC1918 (private) addresses and falls back to 127.0.0.1 with a warning when the only candidate is public, so app host ports are never published on a public interface. Containers still reach each other over the Docker network regardless.

Re-applies the security hunks from the stale PR #398 onto current main; that branch no longer merged because its third hunk (dropping the server->infisical depends_on) already landed separately when Infisical moved behind a compose profile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge main: drop superseded postgres-loopback hunk, keep justfile RFC1918 filter
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 40s
Check / fmt + clippy + build + tests (pull_request) Successful in 1m37s
Integration / integration tests (pull_request) Successful in 8m39s
Create release / Gate (release-branch merges only) (pull_request) Successful in 0s
Create release / Create release from merged PR (pull_request) Has been skipped
1c9c4fa2f0
PR #392 (PMS-496) already hardcoded the dev Postgres host publish to 127.0.0.1 on main, so this branch's compose.dev.yml postgres hunk became redundant and was the sole merge conflict. Resolved by taking main's PMS-496 loopback comments verbatim; compose.dev.yml now matches main exactly. The PG_MEM/"wog" botnet rationale that motivated the change survives in the justfile hunk's comment.

The remaining novel change is the justfile bind-IP discovery RFC1918 filter: `just dev` now keeps only private (10/8, 172.16-31/12, 192.168/16) IPv4 on eth0/br0 and falls back to 127.0.0.1 with a warning when the only candidate is public, so MOKOSH_HOST_BIND_IP (still consumed by the server's BASE_URL) can never resolve to a public address.
nrupard deleted branch fix/dev-db-loopback-bind-on-main 2026-06-29 21:26:35 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
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
psa-systems/mokosh-server!399
No description provided.