{"id":"GHSA-h4g2-xfmw-q2c9","title":"Clauster: Non-loopback deployments can serve the dashboard unauthenticated when auth.enabled is unset","summary":"Clauster: Non-loopback deployments can serve the dashboard unauthenticated when auth.enabled is unset","severity":"high","cwe":["CWE-306"],"vendor":"clauster","product":"clauster","ecosystem":"pip","affected":["clauster <= 0.2.1"],"patched":["clauster 0.2.2"],"published":"2026-07-10","updated":"2026-07-10","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-h4g2-xfmw-q2c9","references":[{"url":"https://github.com/schubydoo/clauster/security/advisories/GHSA-h4g2-xfmw-q2c9"},{"url":"https://github.com/advisories/GHSA-h4g2-xfmw-q2c9"}],"tags":["ghsa","pip"],"ingestedAt":"2026-07-10T21:06:31.324Z","slug":"GHSA-h4g2-xfmw-q2c9","body":"## Overview\n\n### Summary\nA Clauster instance bound to a **non-loopback** address (e.g. `0.0.0.0` or a LAN IP) can serve the entire dashboard and its API **without any authentication** — even when the operator has configured a password — if `auth.enabled` is left at its default (`false`). The operator believes the instance is password-protected; in reality every request is served unauthenticated.\n\n### Impact\nAn unauthenticated attacker with network access to the instance gains full control of the dashboard: list projects, **spawn/stop `claude remote-control` bridges in any project directory**, edit `CLAUDE.md`, read bridge logs, and (where configured) clone repositories. Because bridges run Claude Code against the host's project directories, this is effectively remote code execution in those projects.\n\nLoopback (`127.0.0.1`) deployments need no auth by design and are **not** affected.\n\n### Affected configurations\nAll released versions (≤ 0.2.1) where **all** of the following hold:\n- `host` is a non-loopback address, **and**\n- `auth.password_required: true` and/or `auth.reverse_proxy.enabled: true` is set, **and**\n- `auth.enabled` is left at its default `false`.\n\nDocker deployments are affected: the image binds `0.0.0.0`, and the previously-documented `docker run` command did not set `auth.enabled`.\n\n### Root cause\nTwo layers checked different flags:\n- The runtime auth guard enforces authentication only when `config.auth.enabled` is true; when false it passes **every** request through unauthenticated.\n- The config validator, for a non-loopback bind, required only one of `auth.password_required` / `auth.reverse_proxy.enabled` / `auth.allow_unauthenticated_network` — **not** `auth.enabled`. So a config with a password but `enabled=false` validated, started, and enforced nothing.\n\n### Proof of concept\nWith `host: 0.0.0.0`, `auth.password_required: true`, a valid `auth.password_hash`, and `auth.enabled` unset:\n\n```\ncurl http://<host>:7621/api/instances\n```\n\nreturns `200` with the full instance list and **no credentials**. Setting `auth.enabled: true` returns `401`.\n\n### Patches\nAn upcoming patch release makes the config validator **fail closed**: a non-loopback bind is refused unless authentication is actually enforced — `auth.enabled: true` together with `auth.password_required` (+ a hash) or `auth.reverse_proxy.enabled`, or the explicit `auth.allow_unauthenticated_network` opt-out. The README, `clauster.yml.example`, and Docker docs were corrected to match.\n\n### Workaround\nOn any non-loopback deployment, set `auth.enabled: true` in `clauster.yml` (or `CLAUSTER_AUTH_ENABLED=true`) alongside your existing `auth.password_required` + hash (or reverse-proxy) settings. Alternatively, bind to loopback only and reach it via an SSH tunnel or a trusted authenticating reverse proxy.\n\n### Credit\nFound during an internal security review.\n\n## Affected packages\n\n- `clauster <= 0.2.1`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `clauster 0.2.2`","depth":"twilight","depthScore":41,"depthScoreParts":{"impact":41.3,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}