Skip to content

fix(dashboard): add Host allowlist for trusted reverse proxies - #48954

Closed
moeedahmed wants to merge 2 commits into
NousResearch:mainfrom
moeedahmed:fix/dashboard-host-allowlist-authwidget
Closed

fix(dashboard): add Host allowlist for trusted reverse proxies#48954
moeedahmed wants to merge 2 commits into
NousResearch:mainfrom
moeedahmed:fix/dashboard-host-allowlist-authwidget

Conversation

@moeedahmed

Copy link
Copy Markdown

Adds HERMES_DASHBOARD_ALLOWED_HOSTS env var to allow specific Host headers when the dashboard is bound to 127.0.0.1 behind a trusted reverse proxy like Tailscale Serve.

Also fixes AuthWidget to skip /api/auth/me probe in loopback mode, preventing a reload/flicker loop behind reverse proxies.

Add HERMES_DASHBOARD_ALLOWED_HOSTS so a dashboard bound to 127.0.0.1 can
accept requests forwarded by a trusted local reverse proxy (e.g. Tailscale
Serve) whose Host header is the tailnet DNS name, without binding to a
public interface.

web_server.py:
- Add _normalize_host_header() to extract the bare lowercase host portion
  from a Host header / netloc (plain, host:port, bracketed IPv6, and
  bracketed IPv6 with port).
- Add _dashboard_allowed_host_aliases() reading the comma-separated env var
  into a frozenset of exact aliases (no wildcards).
- Refactor _is_accepted_host() to reuse the normalizer and check the proxy
  aliases before the loopback/exact-match rules; document the lookup chain.

AuthWidget.tsx:
- Skip the /api/auth/me probe entirely in loopback / --insecure mode. The
  shared fetchJSON 401 handler can otherwise turn this expected 401 into a
  reload/flicker loop behind a reverse proxy. The widget already renders
  nothing in this mode, so gate the request on window.__HERMES_AUTH_REQUIRED__.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/security Security vulnerability or hardening comp/cli CLI entry point, hermes_cli/, setup wizard area/auth Authentication, OAuth, credential pools P2 Medium — degraded but workaround exists labels Jun 19, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

  • Well-scoped fix adding Host allowlist for trusted reverse proxies (e.g. Tailscale Serve)
  • Clean refactor: extracts _normalize_host_header into its own function, adds _dashboard_allowed_host_aliases reading from HERMES_DASHBOARD_ALLOWED_HOSTS env var
  • Correct lookup chain: normalized host, then 0.0.0.0 opt-in, then allowlist, then loopback, then exact match
  • IPv6 bracket handling properly preserved in the extracted normalization function
  • AuthWidget.tsx fix: skips /api/auth/me probe when auth is not required, preventing reload/flicker loops behind trusted proxies - good defensive UX fix
  • No wildcards in allowlist (exact match only) is the right security posture
  • Minor formatting fix in AuthWidget.tsx span element is harmless

Reviewed by Hermes Agent

@alt-glitch alt-glitch added comp/dashboard Web dashboard / control panel UI (dashboard/, landing) and removed comp/cli CLI entry point, hermes_cli/, setup wizard labels Jun 26, 2026
# Conflicts:
#	hermes_cli/web_server.py
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused reverse-proxy analysis and the Host-header regression coverage. This automated hermes-sweeper review is closing the PR because its remaining configuration mechanism conflicts with a standing project policy.

  • The PR adds the user-facing non-secret HERMES_DASHBOARD_ALLOWED_HOSTS setting in hermes_cli/web_server.py (commit bc42095ca1f8).
  • AGENTS.md:102-107 requires behavioral settings to be represented in config.yaml, rather than introducing a new HERMES_* environment variable.
  • The separate /api/auth/me reload-loop concern is already handled on current main: web/src/lib/api.ts:319-330 calls that probe with allowUnauthorized: true (introduced by a5c1f925b59a).
  • The linked discussion on fix(dashboard): allow configured reverse proxy hosts #47903 identifies the related config-based route (dashboard.allowed_external_hosts, feat(dashboard): configurable hostname allowlist for tunnel/proxy setups #47560) for maintainers to evaluate.

A focused re-scope to a documented dashboard.* allowlist setting would be the supported alternative. This is a configuration-surface decision, not a judgment on the quality of the reverse-proxy analysis or tests.


Closed as not-planned per standing maintainer policy (env-var-for-config). This is a design-direction decision, not a code-quality judgment — see the Contribution Rubric in AGENTS.md for what the project is looking for. If you believe this policy was misapplied to your change, comment here and a maintainer will take a look.

@teknium1 teknium1 closed this Jul 14, 2026
@teknium1 teknium1 added the sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) label Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P2 Medium — degraded but workaround exists sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants