Skip to content

[Bug]: Gateway auth dispatcher blocks all internal services when mode=trusted-proxy (no shared-secret fallback) #17761

@dashed

Description

@dashed

Summary

authorizeGatewayConnect in src/gateway/auth.ts treats trusted-proxy as a single-mode gate. When proxy auth fails (i.e. the request didn't come from a trusted proxy), the function early-returns with a failure before reaching the shared-secret (token/password) or Tailscale authentication paths. This means all internal consumers that connect directly — without going through the reverse proxy — are unable to authenticate.

Affected internal consumers include: node host, CLI RPC, ACP (Agent Client Protocol), TUI, Discord/Telegram/Slack bridges, status probes, mobile apps, and agent tool calls (cron, sessions, system commands).

This was discovered during investigation of #17270.

Steps to reproduce

  1. Configure gateway with auth.mode: "trusted-proxy" and a auth.token or auth.password
  2. Set up a reverse proxy (e.g. Nginx, Caddy, Authelia) that injects the configured userHeader
  3. Start gateway — browser connections via the reverse proxy work fine
  4. Observe that node host, CLI, and other internal services fail to connect

Expected behavior

Internal services that provide a valid token or password should authenticate successfully, even when the gateway is in trusted-proxy mode. The trusted-proxy check should be the primary auth method, with shared-secret (token/password) as a fallback for direct connections.

Actual behavior

All direct connections fail with the proxy auth failure reason (e.g. trusted_proxy_untrusted_source). The token/password credentials are never checked because the trusted-proxy block early-returns before those code paths.

The relevant code path in authorizeGatewayConnect (src/gateway/auth.ts):

if (auth.mode === "trusted-proxy") {
  // ... proxy auth check ...
  if ("user" in result) {
    return { ok: true, method: "trusted-proxy", user: result.user };
  }
  // ❌ Early return — never reaches token/password/tailscale paths below
  return { ok: false, reason: result.reason };
}

// These paths are never reached when mode=trusted-proxy:
// - Rate limiter setup
// - Tailscale auth
// - Token auth
// - Password auth

Additionally, resolveGatewayAuth excludes trusted-proxy from the allowTailscale default:

const allowTailscale =
  authConfig.allowTailscale ?? (params.tailscaleMode === "serve" && mode !== "password");

This doesn't explicitly exclude trusted-proxy, but the Tailscale check happens after the trusted-proxy block, so it's unreachable anyway.

OpenClaw version

All versions since trusted-proxy mode was introduced (#1560).

Operating system

All platforms.

Install method

All install methods.

Impact and severity

High — any deployment using trusted-proxy mode has all internal services broken. This includes:

Consumer Impact
Node host Cannot connect → nodes offline
CLI RPC Cannot authenticate → CLI non-functional
ACP Cannot connect → agent tools degraded
TUI Cannot authenticate
Agent tool calls Cron, sessions, system commands all fail
Bridges (Discord, Telegram, etc.) Cannot connect if running externally
Status probes Health checks fail

Users may not notice immediately because browser connections through the reverse proxy continue to work.

Additional information

Related issues:

Fix: #17746 adds an inline shared-secret fallback within the trusted-proxy block — when proxy auth fails and a token/password is configured, it attempts shared-secret auth (with rate limiting) before returning failure.

Metadata

Metadata

Assignees

Labels

No labels
No labels

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