Skip to content

Security and the hub token

The hub page and every /api/* route need a token. By default the hub listens on loopback only, but loopback is not a user boundary: any account on the machine can reach a loopback port. The hub API also hands out the terminal token, and the terminal can run any command.

  • The token is in ~/.claude-hub/token. The hub makes it on the first run, with file mode 600, and keeps it across restarts.
  • The startup banner prints the URL with the token: http://localhost:3540/?token=<token>. --open opens that URL.
  • When a request has the right token, the hub sets an HttpOnly, SameSite=Strict cookie named hub_token and redirects to the same URL without the token. The cookie lasts 400 days, so later visits and the installed app need no token.
  • Without the token or the cookie, the page shows a locked screen, and the API answers 401.
Hub pageHub serverKanban iframeGET /?token=<token>the URL from the banner or --open302 to /, Set-Cookie: hub_tokenHttpOnly, SameSite=Strict, 400 daysGET /api/config with the cookiethe app URLs and the terminal tokeniframe src …/#t=<terminal token>a fragment: the browser does not send itGET /api/* with no cookie401, and the page shows the locked screen
How the browser gets the hub token and the terminal token

Scripts, styles, icons, and the web app manifest do not need the token. They hold no secrets, and Chrome fetches the manifest without cookies.

Delete ~/.claude-hub/token and restart the hub. Every browser then needs the new URL from the banner once.

The embedded terminal has its own token. The hub makes a new one each time it starts. It gives the token to Kanban in the URL fragment (#t=…), which the browser never sends to a server, so the token does not reach a server log or a Referer header. See Embedded terminal.

The four tools have no login of their own. Each one checks every request:

  • Host. A request must be addressed to localhost or a loopback address. This blocks DNS rebinding.
  • Origin. A write request must come from the tool itself or from the hub.
  • Framing. Only the hub and the tool’s own pages can frame it. A page on the internet cannot.

The hub forwards postMessage messages only to and from the four tool origins, and each tool accepts messages only from the hub.

By default the hub binds to 127.0.0.1. To reach it from another machine, set the bind address and add the host name you will use:

Terminal window
npx claude-code-hub --host 0.0.0.0 --allowed-hosts=my-box.local

The hub prints a warning when it listens on a non-loopback address. The hub page still needs the token, but the four tools have no login, so anyone who can reach their ports can use them. Do this only on a network you trust. The embedded terminal is off in this mode.