openclaw - ✅(Solved) Fix [Bug]: `gateway.auth.mode=trusted-proxy` still accepts local password auth fallback when `OPENCLAW_GATEWAY_PASSWORD` (or `gateway.auth.password`) is set [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#78684Fetched 2026-05-07 03:33:51
View on GitHub
Comments
1
Participants
2
Timeline
15
Reactions
2
Author
Assignees
Timeline (top)
subscribed ×6mentioned ×3cross-referenced ×2labeled ×2

In trusted-proxy mode, gateway auth is expected to be derived from trusted proxy identity headers. Current behavior includes an additional local-direct fallback: when trusted-proxy checks fail on loopback and a password is configured, authorizeGatewayConnect returns password auth success (method: "password"). This creates a second auth path under mode: "trusted-proxy".

Root Cause

In trusted-proxy mode, gateway auth is expected to be derived from trusted proxy identity headers. Current behavior includes an additional local-direct fallback: when trusted-proxy checks fail on loopback and a password is configured, authorizeGatewayConnect returns password auth success (method: "password"). This creates a second auth path under mode: "trusted-proxy".

Fix Action

Fixed

PR fix notes

PR #78692: fix(gateway): remove password fallback from trusted-proxy auth mode (#78684)

Description (problem / solution / changelog)

Problem

When gateway.auth.mode is trusted-proxy, a failed proxy identity check could still succeed via local-direct password auth if OPENCLAW_GATEWAY_PASSWORD (or gateway.auth.password) was configured. This creates a second undocumented auth path that violates the intent of trusted-proxy mode.

Source: src/gateway/auth.ts:469-487 — after authorizeTrustedProxy returns a non-user result, the code falls through to authorizePasswordAuth when localDirect && auth.password && connectAuth?.password.

Fixes #78684.

Fix

Remove the password fallback branch from the auth.mode === "trusted-proxy" block. A failed trusted-proxy check now always returns { ok: false, reason: result.reason } regardless of whether a password is configured.

Audit A — existing helper check

No new auth predicate needed. The authorizeTrustedProxy + authorizePasswordAuth functions already exist; this is a branch removal not a new abstraction.

Audit B — shared caller check

authorizeGatewayConnect is called in 2 test-convenience helpers within auth.test.ts and in gateway connection flows. The function signature is unchanged; only the internal branching for mode === "trusted-proxy" is affected.

Audit C — rival PR scan

No rival PR open for #78684 at scout time.

Real behavior proof

Updated src/gateway/auth.test.ts:

  • The existing "accepts local-direct password fallback when trusted-proxy auth fails" test now asserts ok: false with reason: "trusted_proxy_loopback_source" (the correct fail-closed behavior).
  • The two tests for wrong-password fallback and rate-limit-before-fallback are removed — they tested the removed code path.
  • All 207 tests in auth test suite pass.
  • pnpm -s tsgo:core clean.

Co-authored-by: hclsys

Changed files

  • CHANGELOG.md (modified, +2/-0)
  • src/gateway/auth.test.ts (modified, +4/-43)
  • src/gateway/auth.ts (modified, +0/-20)

PR #78694: fix(gateway): remove password fallback in trusted-proxy auth mode

Description (problem / solution / changelog)

Summary

Closes #78684.

When gateway.auth.mode is "trusted-proxy", failed trusted-proxy checks now fail closed instead of falling back to local-direct password authentication.

Problem

In the authorizeGatewayConnectCore function, when trusted-proxy identity verification failed on a local-direct (loopback) request, the code would check for a configured password and attempt password auth as a fallback. This created a second, unintended authentication path that bypasses the trusted-proxy requirement.

Fix

Remove the conditional password fallback block within the trusted-proxy code path (lines 469–488 of src/gateway/auth.ts). When auth.mode === "trusted-proxy", authentication now either succeeds via the proxy or fails — no fallback.

Testing

  • Updated src/gateway/auth.test.ts — the previous test asserting password fallback success now asserts rejection (trusted_proxy_loopback_source)
  • Removed obsolete wrong-password and rate-limit-before-fallback tests (the fallback code path no longer exists)
  • All 207 auth tests pass across 3 shards (gateway-core, gateway-server, gateway-client)

Impact

Users relying on the implicit local-direct password fallback in trusted-proxy mode will need to either:

  1. Switch to auth.mode: "password" for local-only deployments
  2. Ensure their local CLI connects through the trusted proxy

Changed files

  • src/gateway/auth.test.ts (modified, +5/-44)
  • src/gateway/auth.ts (modified, +0/-20)

Code Example

:489:src/gateway/auth.ts
  if (auth.mode === "trusted-proxy") {
    ...
    const result = authorizeTrustedProxy({ ... });
    if ("user" in result) {
      ...
      return { ok: true, method: "trusted-proxy", user: result.user };
    }
    if (localDirect && auth.password && connectAuth?.password) {
      ...
      return authorizePasswordAuth({
        authPassword: auth.password,
        connectPassword: connectAuth.password,
        ...
      });
    }
    return { ok: false, reason: result.reason };
  }


:979:src/gateway/auth.test.ts
    it("accepts local-direct password fallback when trusted-proxy auth fails", async () => {
      const limiter = createLimiterSpy();
      const res = await authorizeLocalDirect({
        password: "local-password",
        connectPassword: "local-password",
        rateLimiter: limiter,
      });

      expect(res).toEqual({ ok: true, method: "password" });
    });
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

In trusted-proxy mode, gateway auth is expected to be derived from trusted proxy identity headers. Current behavior includes an additional local-direct fallback: when trusted-proxy checks fail on loopback and a password is configured, authorizeGatewayConnect returns password auth success (method: "password"). This creates a second auth path under mode: "trusted-proxy".

Steps to reproduce

  1. Configure gateway auth mode as trusted-proxy and set a password secret as well.
  2. Send a loopback request (same host) that does not satisfy trusted-proxy identity checks.
  3. Include connectAuth.password matching configured password.
  4. Observe successful auth via password fallback.

Expected behavior

When gateway.auth.mode is trusted-proxy, authentication should require trusted-proxy conditions only (or fail closed), unless an explicit separate compatibility mode is enabled.

Actual behavior

Trusted-proxy failures can still authenticate via local-direct password fallback.

OpenClaw version

2026.5.4

Operating system

Ubuntu 24.04 / Windows 11

Install method

npm global

Model

anthropic/claude-sonnet-4.5

Provider / routing chain

anthropic

Additional provider/model setup details

No response

Logs, screenshots, and evidence

:489:src/gateway/auth.ts
  if (auth.mode === "trusted-proxy") {
    ...
    const result = authorizeTrustedProxy({ ... });
    if ("user" in result) {
      ...
      return { ok: true, method: "trusted-proxy", user: result.user };
    }
    if (localDirect && auth.password && connectAuth?.password) {
      ...
      return authorizePasswordAuth({
        authPassword: auth.password,
        connectPassword: connectAuth.password,
        ...
      });
    }
    return { ok: false, reason: result.reason };
  }


:979:src/gateway/auth.test.ts
    it("accepts local-direct password fallback when trusted-proxy auth fails", async () => {
      const limiter = createLimiterSpy();
      const res = await authorizeLocalDirect({
        password: "local-password",
        connectPassword: "local-password",
        rateLimiter: limiter,
      });

      expect(res).toEqual({ ok: true, method: "password" });
    });

Impact and severity

High/critical security footgun on shared-host deployments: trusted-proxy mode can be bypassed to password auth locally when a password is present, which weakens mode isolation and operator expectation that trusted-proxy is the sole auth method.

Additional information

assertGatewayAuthConfigured forbids token coexistence in trusted-proxy mode, but does not forbid password coexistence, which allows this fallback behavior.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

When gateway.auth.mode is trusted-proxy, authentication should require trusted-proxy conditions only (or fail closed), unless an explicit separate compatibility mode is enabled.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: `gateway.auth.mode=trusted-proxy` still accepts local password auth fallback when `OPENCLAW_GATEWAY_PASSWORD` (or `gateway.auth.password`) is set [2 pull requests, 1 comments, 2 participants]