Clauster: Missing Authentication Bypass on Non-Loopback Dashboard
Clauster instances bound to a public or LAN address silently skip all authentication when auth.enabled is left at its default of false, letting anyone on the network take full control of the dashboard
The problem
Clauster splits authentication across two independent layers: a runtime middleware that gates requests behind `auth.enabled`, and a config validator that checks whether *some* auth-related flag (password, reverse proxy, or explicit unauthenticated opt-out) is set.
These two layers did not agree.
An operator who set `auth.password_required: true` and supplied a password hash would pass config validation and start the server believing it was protected. But because `auth.enabled` defaults to `false`, the runtime guard passed every single request through without checking credentials.
This affected all non-loopback binds, including the Docker image which binds `0.0.0.0` by default.
Proof of concept
A working proof-of-concept for this issue in clauster, with the exact payload below.
# clauster.yml (vulnerable config)
# host: 0.0.0.0
# auth:
# enabled: false # <-- default, not set by operator
# password_required: true
# password_hash: "<bcrypt>"
# Exploit: unauthenticated access to protected instance
curl http://<host>:7621/api/instances
# Returns HTTP 200 + full instance list with no credentialsThe root cause is CWE-306 (Missing Authentication for Critical Function): the config validator accepted a config that *declared* authentication intent without *enforcing* it at runtime. The patch fixes this by making the validator fail-closed: starting with 0.2.2, a non-loopback bind is rejected at startup unless `auth.enabled: true` is present together with either `auth.password_required` (plus a hash) or `auth.reverse_proxy.enabled`.
Operators who truly want no auth must explicitly set `auth.allow_unauthenticated_network: true`.
Because the guard was a simple boolean short-circuit (`if not config.auth.enabled: return next(request)`), no special headers or encoding were needed. A plain unauthenticated HTTP GET to any API endpoint was sufficient.
The fix
Upgrade to clauster 0.2.2. If an immediate upgrade is not possible, add `auth.enabled: true` to `clauster.yml` (or set `CLAUSTER_AUTH_ENABLED=true`) alongside your existing password or reverse-proxy config. Alternatively, bind to loopback only (`host: 127.0.0.1`) and expose the instance through a trusted SSH tunnel or authenticating reverse proxy.
Related research
- high · 8.3CVE-2026-49471CVE-2026-49471: serena-agent Unauthenticated Flask Dashboard Enables DNS Rebinding to RCE
- high · 8.4CVE-2026-55786CVE-2026-55786: flyto-core Unauthenticated OS Command Injection via HTTP MCP
- critical · 9.8CVE-2026-50027CVE-2026-50027: mcp-memory-service Missing Authentication on Document API Endpoints
- critical · 10CVE-2026-49257CVE-2026-49257: mcp-pinot-server Unauthenticated Remote Tool Invocation