absurd: unauthenticated Habitat dashboard on all interfaces
absurd Habitat dashboard - no authentication, binds to all network interfaces by default and has no Host or Origin check, exposing task secrets and task retry to the network and to DNS rebinding (GHSA-6wff-4mpf-gpj8)
Unpatched. Reported privately via GitHub Security Advisory on 2026-07-12; the 90-day coordinated-disclosure window passed, and the final 2026-11-03 deadline set in our 2026-10-20 notice expired with no response from the maintainer.
- Product
- absurd (Habitat dashboard) in earendil-works/absurd
- Affected versions
- absurd through 0.5.1 and main (checked at HEAD 3cfc64f).
- Severity
- MEDIUM
- Status
- Unpatched
- Weaknesses
- CWE-306Missing Authentication for Critical Functionality
- CWE-350Reliance on Reverse DNS Resolution for a Security-Critical Action
- CWE-1327Binding to an Unrestricted IP Address
- GitHub advisory
- GHSA-6wff-4mpf-gpj8
Private; in triage, not yet published by the maintainer - CVE
- Pending (requested via MITRE CNA-LR)
- Published
- Credit
- Finder: Aaron Elijah Mars of Aeon. Tool: Aeon (https://www.aeon.fun).
What operators should do now
No upstream patch is available yet. Anyone running Habitat should restrict who can reach it until an official fix is released.
- Bind Habitat to loopback explicitly: start it with
--listen 127.0.0.1:7890or setHABITAT_LISTEN=127.0.0.1:7890. - If the dashboard must be reachable from other machines, put it behind an authenticating reverse proxy that also only accepts the expected
Hostvalue, and firewall TCP 7890 from everything else. - Stop Habitat when you are not using it, since a loopback bind alone does not stop DNS rebinding from a page open in your browser.
- If modifying the code, apply the small patch from our report: change
defaultListenAddressinhabitat/internal/config/config.goto127.0.0.1:7890and add a middleware inhabitat/internal/server/server.gothat rejects requests whoseHostheader is not an expected local or operator-configured name. - Avoid placing long-lived secrets in task parameters or headers; pass references and load the secret inside the worker instead.
Impact and reach
Habitat is documented as being served at http://localhost:7890, which suggests it is local only. In Go, the default listen address :7890 binds every interface, so any host on the same LAN, VPC, container network or node can call the API with no credentials. The JSON API returns task params, headers, retry strategy, checkpoint state and event payloads verbatim, and POST /api/tasks/retry lets the caller re-enqueue or extend attempts on arbitrary tasks.
Because there is no Host allowlist, a web page the operator visits can rebind a hostname it controls to the dashboard's address and then read the API as if it were same-origin. That reaches the data and the retry action even on a deployment bound to loopback. A working exploit is withheld.
How the dashboard is exposed
The listen address defaults to :7890 and is passed straight to net.Listen. The route table wires every API handler, including the retry action, with no authentication, and the only wrappers are request logging and base-path rewriting, neither of which checks Host or Origin:
- Default listen address on all interfaces: habitat/internal/config/config.go#L15
- Listener opened on the configured address: habitat/internal/server/server.go#L66-L76
- Unauthenticated API routes, including POST /api/tasks/retry: habitat/internal/server/server.go#L113-L130
- Logging and base-path wrappers with no Host or Origin check: habitat/internal/server/server.go#L103-L111 and server.go#L132-L173
Disclosure timeline
- Vulnerability reported privately via GitHub Security Advisory (GHSA-6wff-4mpf-gpj8).
- First follow-up comment posted on the advisory (31 days in triage).
- Second follow-up comment posted on the advisory (48 days in triage).
- Third follow-up comment posted on the advisory (67 days in triage).
- Coordinated-disclosure notice posted on the advisory after the 90-day window passed, setting a deadline of 2026-11-03.
- Coordinated-disclosure deadline expired with no response from the maintainer; sink verified still present at HEAD 3cfc64f and in release 0.5.1.
- Public advisory published; CVE requested via MITRE CNA-LR.
References
- Affected repository: earendil-works/absurd
- GitHub Security Advisory: GHSA-6wff-4mpf-gpj8 (private; in triage)