Skip to content

[Bug]: dashboard --tui: WebSocket rejected for non-loopback clients even with --insecure / --host 0.0.0.0 #33265

@KikiDev44

Description

@KikiDev44

Bug Description

When running hermes dashboard --host 0.0.0.0 --insecure --tui and accessing the dashboard from another host on the local network, the TUI interface never loads. The page appears but stays blank/stuck indefinitely. The WebSocket connection is silently rejected server-side for any non-loopback client IP, even when --insecure is explicitly passed.

Steps to Reproduce

  1. Start the dashboard bound to all interfaces:
    hermes dashboard --host 0.0.0.0 --insecure --tui

  2. Open the dashboard URL from a second machine on the same LAN (non-loopback IP).

  3. Observe that the TUI never initializes, HTTP loads, WebSocket does not.

Expected Behavior

When --insecure is passed together with --host 0.0.0.0, WebSocket connections from non-loopback LAN clients should be accepted, consistent with the intent of the --insecure flag.

Actual Behavior

The WebSocket handshake is rejected for any non-loopback client.host. The TUI stays blank. No error is shown to the user, the connection is dropped silently.

Affected Component

Configuration (config.yaml, .env, hermes setup)

Messaging Platform (if gateway-related)

N/A (CLI only)

Debug Report

-\-

Operating System

Ubuntu 24.04

Python Version

3.14.3

Hermes Version

v0.14.0

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

_ws_client_is_allowed() in hermes_cli/web_server.py (~line 3325) unconditionally blocks non-loopback IPs:

pythondef _ws_client_is_allowed(ws: "WebSocket") -> bool:
    client_host = ws.client.host if ws.client else ""
    if not client_host:
        return True
    return client_host in _LOOPBACK_HOSTS

start_server() receives allow_public from the --insecure flag but never writes it to app.state, so _ws_client_is_allowed cannot read it.

Proposed Fix (optional)

Two minimal changes to hermes_cli/web_server.py:

  1. In start_server(), persist allow_public on app.state directly after the existing bound_host/bound_port assignments (~line 4718):
pythonapp.state.bound_host = host
app.state.bound_port = port
**app.state.allow_public = allow_public  # add this**
  1. Extend _ws_client_is_allowed() to respect --insecure:
pythondef _ws_client_is_allowed(ws: "WebSocket") -> bool:
    """Allows loopback clients only, unless --insecure made the server public."""
    if getattr(app.state, "allow_public", False):
        return True
    client_host = ws.client.host if ws.client else ""
    if not client_host:
        return True
    return client_host in _LOOPBACK_HOSTS

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/configConfig system, migrations, profilescomp/cliCLI entry point, hermes_cli/, setup wizardtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions