fix(gateway): align insecure-auth toggle messaging

This commit is contained in:
Peter Steinberger
2026-02-21 12:55:18 +01:00
parent 810218756d
commit 99048dbec2
8 changed files with 35 additions and 17 deletions

View File

@@ -204,8 +204,8 @@ The Gateway treats these as **claims** and enforces server-side allowlists.
- **Local** connects include loopback and the gateway hosts own tailnet address
(so samehost tailnet binds can still autoapprove).
- All WS clients must include `device` identity during `connect` (operator + node).
Control UI can omit it **only** when `gateway.controlUi.allowInsecureAuth` is enabled
(or `gateway.controlUi.dangerouslyDisableDeviceAuth` for break-glass use).
Control UI can omit it **only** when `gateway.controlUi.dangerouslyDisableDeviceAuth`
is enabled for break-glass use.
- Non-local connections must sign the server-provided `connect.challenge` nonce.
## TLS + pinning

View File

@@ -127,7 +127,7 @@ High-signal `checkId` values you will most likely see in real deployments (not e
| `gateway.http.no_auth` | warn/critical | Gateway HTTP APIs reachable with `auth.mode="none"` | `gateway.auth.mode`, `gateway.http.endpoints.*` | no |
| `gateway.tools_invoke_http.dangerous_allow` | warn/critical | Re-enables dangerous tools over HTTP API | `gateway.tools.allow` | no |
| `gateway.tailscale_funnel` | critical | Public internet exposure | `gateway.tailscale.mode` | no |
| `gateway.control_ui.insecure_auth` | critical | Token-only over HTTP, no device identity | `gateway.controlUi.allowInsecureAuth` | no |
| `gateway.control_ui.insecure_auth` | critical | Insecure-auth toggle enabled | `gateway.controlUi.allowInsecureAuth` | no |
| `gateway.control_ui.device_auth_disabled` | critical | Disables device identity check | `gateway.controlUi.dangerouslyDisableDeviceAuth` | no |
| `hooks.token_too_short` | warn | Easier brute force on hook ingress | `hooks.token` | no |
| `hooks.request_session_key_enabled` | warn/critical | External caller can choose sessionKey | `hooks.allowRequestSessionKey` | no |
@@ -143,9 +143,9 @@ High-signal `checkId` values you will most likely see in real deployments (not e
## Control UI over HTTP
The Control UI needs a **secure context** (HTTPS or localhost) to generate device
identity. If you enable `gateway.controlUi.allowInsecureAuth`, the UI falls back
to **token-only auth** and skips device pairing when device identity is omitted. This is a security
downgrade—prefer HTTPS (Tailscale Serve) or open the UI on `127.0.0.1`.
identity. `gateway.controlUi.allowInsecureAuth` does **not** bypass secure-context,
device-identity, or device-pairing checks. Prefer HTTPS (Tailscale Serve) or open
the UI on `127.0.0.1`.
For break-glass scenarios only, `gateway.controlUi.dangerouslyDisableDeviceAuth`
disables device identity checks entirely. This is a severe security downgrade;

View File

@@ -150,7 +150,7 @@ OpenClaw **blocks** Control UI connections without device identity.
- `https://<magicdns>/` (Serve)
- `http://127.0.0.1:18789/` (on the gateway host)
**Downgrade example (token-only over HTTP):**
**Insecure-auth toggle behavior:**
```json5
{
@@ -162,8 +162,22 @@ OpenClaw **blocks** Control UI connections without device identity.
}
```
This disables device identity + pairing for the Control UI (even on HTTPS). Use
only if you trust the network.
`allowInsecureAuth` does not bypass Control UI device identity or pairing checks.
**Break-glass only:**
```json5
{
gateway: {
controlUi: { dangerouslyDisableDeviceAuth: true },
bind: "tailnet",
auth: { mode: "token", token: "replace-me" },
},
}
```
`dangerouslyDisableDeviceAuth` disables Control UI device identity checks and is a
severe security downgrade. Revert quickly after emergency use.
See [Tailscale](/gateway/tailscale) for HTTPS setup guidance.

View File

@@ -33,7 +33,7 @@ export const FIELD_HELP: Record<string, string> = {
"gateway.controlUi.allowedOrigins":
"Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com).",
"gateway.controlUi.allowInsecureAuth":
"Allow Control UI auth over insecure HTTP (token-only; not recommended).",
"Insecure-auth toggle; Control UI still enforces secure context + device identity unless dangerouslyDisableDeviceAuth is enabled.",
"gateway.controlUi.dangerouslyDisableDeviceAuth":
"DANGEROUS. Disable Control UI device identity checks (token/password only).",
"gateway.http.endpoints.chatCompletions.enabled":

View File

@@ -114,7 +114,7 @@ export const FIELD_LABELS: Record<string, string> = {
"gateway.controlUi.basePath": "Control UI Base Path",
"gateway.controlUi.root": "Control UI Assets Root",
"gateway.controlUi.allowedOrigins": "Control UI Allowed Origins",
"gateway.controlUi.allowInsecureAuth": "Allow Insecure Control UI Auth",
"gateway.controlUi.allowInsecureAuth": "Insecure Control UI Auth Toggle",
"gateway.controlUi.dangerouslyDisableDeviceAuth": "Dangerously Disable Control UI Device Auth",
"gateway.http.endpoints.chatCompletions.enabled": "OpenAI Chat Completions Endpoint",
"gateway.reload.mode": "Config Reload Mode",

View File

@@ -70,7 +70,11 @@ export type GatewayControlUiConfig = {
root?: string;
/** Allowed browser origins for Control UI/WebChat websocket connections. */
allowedOrigins?: string[];
/** Allow token-only auth over insecure HTTP (default: false). */
/**
* Insecure-auth toggle.
* Control UI still requires secure context + device identity unless
* dangerouslyDisableDeviceAuth is enabled.
*/
allowInsecureAuth?: boolean;
/** DANGEROUS: Disable device identity checks for the Control UI (default: false). */
dangerouslyDisableDeviceAuth?: boolean;

View File

@@ -341,8 +341,7 @@ export function attachGatewayWsMessageHandler(params: {
isControlUi && configSnapshot.gateway?.controlUi?.allowInsecureAuth === true;
const disableControlUiDeviceAuth =
isControlUi && configSnapshot.gateway?.controlUi?.dangerouslyDisableDeviceAuth === true;
// `allowInsecureAuth` is retained for compatibility, but must not bypass
// secure-context/device-auth requirements.
// `allowInsecureAuth` must not bypass secure-context/device-auth requirements.
const allowControlUiBypass = disableControlUiDeviceAuth;
const device = disableControlUiDeviceAuth ? null : deviceRaw;
@@ -429,7 +428,8 @@ export function attachGatewayWsMessageHandler(params: {
const canSkipDevice = sharedAuthOk;
if (isControlUi && !allowControlUiBypass) {
const errorMessage = "control ui requires HTTPS or localhost (secure context)";
const errorMessage =
"control ui requires device identity (use HTTPS or localhost secure context)";
markHandshakeFailure("control-ui-insecure-auth", {
insecureAuthConfigured: allowInsecureControlUi,
});

View File

@@ -349,9 +349,9 @@ function collectGatewayConfigFindings(
findings.push({
checkId: "gateway.control_ui.insecure_auth",
severity: "critical",
title: "Control UI allows insecure HTTP auth",
title: "Control UI insecure auth toggle enabled",
detail:
"gateway.controlUi.allowInsecureAuth=true is a legacy insecure-auth toggle; Control UI still enforces secure context and device identity unless dangerouslyDisableDeviceAuth is enabled.",
"gateway.controlUi.allowInsecureAuth=true does not bypass secure context or device identity checks; only dangerouslyDisableDeviceAuth disables Control UI device identity checks.",
remediation: "Disable it or switch to HTTPS (Tailscale Serve) or localhost.",
});
}