Skip to content

fix(gateway): allow local connections in trusted-proxy auth mode#54426

Closed
t2wei wants to merge 1 commit intoopenclaw:mainfrom
t2wei:fix/trusted-proxy-local-acpx-bypass
Closed

fix(gateway): allow local connections in trusted-proxy auth mode#54426
t2wei wants to merge 1 commit intoopenclaw:mainfrom
t2wei:fix/trusted-proxy-local-acpx-bypass

Conversation

@t2wei
Copy link
Copy Markdown

@t2wei t2wei commented Mar 25, 2026

Summary

  • When gateway.auth.mode is trusted-proxy, ACPX child processes connecting back to the gateway via localhost are rejected because they lack the proxy user header (e.g. x-amzn-oidc-data)
  • The authorizeGatewayConnect() trusted-proxy branch performs a hard early return without considering localDirect, even though the variable is already computed at that point
  • This breaks ACP functionality in any trusted-proxy deployment (e.g. behind AWS ALB with OIDC auth)

Fix

When trusted-proxy auth fails and the connection is a local direct request (localDirect === true), fall through with method: "none" instead of rejecting. These connections originate from processes spawned by the gateway itself (ACPX/Codex CLI), so they are inherently trusted.

Test plan

  • Deploy with gateway.auth.mode: "trusted-proxy" behind a reverse proxy
  • Verify external connections still require the proxy user header
  • Verify ACP spawn works (ACPX child process connects via localhost)
  • Verify Control UI still works through the proxy

🤖 Generated with Claude Code

When gateway.auth.mode is "trusted-proxy", local direct connections
(e.g. ACPX child processes connecting back to the gateway) are rejected
because they lack the proxy user header. This breaks ACP functionality
in any trusted-proxy deployment.

The trusted-proxy branch in authorizeGatewayConnect() performs a hard
early return without considering localDirect — even though the variable
is already computed. Add a fallback that allows local direct connections
when trusted-proxy auth fails, since these connections originate from
processes spawned by the gateway itself.
@t2wei t2wei requested a review from a team as a code owner March 25, 2026 11:08
@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS labels Mar 25, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 25, 2026

Greptile Summary

This PR fixes a regression in trusted-proxy auth mode where ACPX child processes connecting back to the gateway via localhost were incorrectly rejected because they don't carry the expected proxy user header (e.g. x-amzn-oidc-data). The single-line fix inserts a localDirect check after authorizeTrustedProxy fails, returning { ok: true, method: "none", user: "local" } for loopback connections — consistent with how the gateway handles local traffic in non-proxy auth modes.

Key points:

  • Logic is correct: isLocalDirectRequest resolves the actual client IP through forwarding headers, so a proxied external request with host: localhost still fails the loopback-address test and cannot exploit this path.
  • Early-exit paths are unaffected: The trusted_proxy_config_missing and trusted_proxy_no_proxies_configured guards run before the new check, so a misconfigured deployment does not accidentally open a bypass.
  • No test coverage added: The new bypass path is security-sensitive and completely untested. The existing describe("trusted-proxy auth", ...) suite should be extended with at least: a passing local connection case, a proxied request that remains rejected despite a localish host header, and confirmation that the early-exit guards still block local connections when trustedProxies is empty.

Confidence Score: 4/5

  • Safe to merge with the understanding that test coverage for the new bypass path should follow in a near-term commit.
  • The fix is minimal, targeted, and logically sound. The existing isLocalDirectRequest implementation is robust against header-injection spoofing by external clients, so no new attack surface is introduced. The only concrete gap is the absence of unit tests for the new code path — important for a security-adjacent change but not a blocker given the correctness analysis.
  • No files require special attention beyond the missing test cases in src/gateway/auth.test.ts.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/auth.ts
Line: 401-403

Comment:
**Missing test coverage for new bypass path**

The new `localDirect` bypass in `trusted-proxy` mode has no corresponding test cases in `auth.test.ts`. This is a security-sensitive code path (it allows requests to skip authentication entirely), and the existing `describe("trusted-proxy auth", ...)` suite doesn't exercise it at all.

At minimum, tests should cover:
- A localhost connection without proxy headers is accepted with `{ method: "none", user: "local" }`.
- A proxied request (correct remote addr, missing user header, `host: localhost`) is still rejected (i.e., `isLocalDirectRequest` returns false for proxied traffic even when `host` is localish).
- The early-exit paths (`trusted_proxy_config_missing`, `trusted_proxy_no_proxies_configured`) still reject local connections (confirming they are intentionally excluded from the bypass).

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(gateway): allow local connections in..." | Re-trigger Greptile

Comment thread src/gateway/auth.ts
Comment on lines +401 to +403
if (localDirect) {
return { ok: true, method: "none", user: "local" };
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing test coverage for new bypass path

The new localDirect bypass in trusted-proxy mode has no corresponding test cases in auth.test.ts. This is a security-sensitive code path (it allows requests to skip authentication entirely), and the existing describe("trusted-proxy auth", ...) suite doesn't exercise it at all.

At minimum, tests should cover:

  • A localhost connection without proxy headers is accepted with { method: "none", user: "local" }.
  • A proxied request (correct remote addr, missing user header, host: localhost) is still rejected (i.e., isLocalDirectRequest returns false for proxied traffic even when host is localish).
  • The early-exit paths (trusted_proxy_config_missing, trusted_proxy_no_proxies_configured) still reject local connections (confirming they are intentionally excluded from the bypass).
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/auth.ts
Line: 401-403

Comment:
**Missing test coverage for new bypass path**

The new `localDirect` bypass in `trusted-proxy` mode has no corresponding test cases in `auth.test.ts`. This is a security-sensitive code path (it allows requests to skip authentication entirely), and the existing `describe("trusted-proxy auth", ...)` suite doesn't exercise it at all.

At minimum, tests should cover:
- A localhost connection without proxy headers is accepted with `{ method: "none", user: "local" }`.
- A proxied request (correct remote addr, missing user header, `host: localhost`) is still rejected (i.e., `isLocalDirectRequest` returns false for proxied traffic even when `host` is localish).
- The early-exit paths (`trusted_proxy_config_missing`, `trusted_proxy_no_proxies_configured`) still reject local connections (confirming they are intentionally excluded from the bypass).

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f45ff858ed

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/gateway/auth.ts
Comment on lines +401 to +402
if (localDirect) {
return { ok: true, method: "none", user: "local" };
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate trusted-proxy local fallback to verified internal callers

Allowing localDirect to unconditionally return ok: true here turns any loopback request into authenticated access when trusted-proxy checks fail. localDirect is based on loopback/local-host heuristics, so a reverse proxy running on the same host can satisfy it (for example by forwarding with a local Host header and missing/stripped proxy headers), which lets external traffic bypass trusted-proxy identity/header enforcement entirely. This broadens auth bypass far beyond ACPX child processes and weakens trusted-proxy mode in common colocated-proxy deployments.

Useful? React with 👍 / 👎.

t2wei pushed a commit to t2wei/openclaw that referenced this pull request Mar 27, 2026
ACPX child processes connect back to the gateway via localhost without
proxy headers, causing trusted_proxy_user_missing rejection. Add
localDirect fallback in the trusted-proxy auth branch.

Upstream PR: openclaw#54426

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 26, 2026

Closing this as duplicate or superseded after Codex automated review.

Close #54426 as superseded by #69066. The PR addresses real trusted-proxy/internal-caller pain, but current main intentionally fails closed for loopback-source trusted-proxy requests, and #69066 is the open canonical design track for separating internal service identity from user auth rather than merging this broad localDirect bypass.

Best possible solution:

Close #54426 as superseded by #69066. Keep current main's fail-closed trusted-proxy loopback behavior, and pursue a first-class internal service identity or another explicitly gated fallback through the canonical trusted-proxy auth design track rather than merging this blanket localDirect method:none bypass.

What I checked:

  • Current trusted-proxy auth fails closed on loopback sources: authorizeTrustedProxy returns trusted_proxy_loopback_source for loopback remote addresses, and authorizeGatewayConnect returns that trusted-proxy failure directly without falling through to method:"none" for localDirect. (src/gateway/auth.ts:278, 6cd047e7c270)
  • Regression tests reject this PR's bypass shape: The local-direct trusted-proxy test suite asserts direct loopback requests are rejected with trusted_proxy_loopback_source, including no credentials, a valid token, a wrong token, and no configured local token. (src/gateway/auth.test.ts:901, 6cd047e7c270)
  • Docs define non-loopback trusted proxy as the supported boundary: Trusted proxy docs say loopback-source requests are rejected, same-host loopback reverse proxies do not satisfy trusted-proxy auth, and same-host setups should use token/password auth or route through a non-loopback trusted proxy address. Public docs: docs/gateway/trusted-proxy-auth.md. (docs/gateway/trusted-proxy-auth.md:93, 6cd047e7c270)
  • Protocol docs keep internal backend relief on shared auth, not trusted-proxy bypass: The protocol docs reserve direct-loopback backend device-less operation for gateway-client backend RPCs authenticated with the shared gateway token/password, while identity-bearing trusted-proxy auth is described as non-loopback. Public docs: docs/gateway/protocol.md. (docs/gateway/protocol.md:113, 6cd047e7c270)
  • Canonical superseding item exists: Provided GitHub context for [RFC] Separate internal service identity from user auth in OpenClaw gateway #69066 shows an open RFC specifically separating internal service identity from user auth, listing fix(gateway): allow local connections in trusted-proxy auth mode #54426 among PRs it would supersede or subsume and framing that as the durable fix for trusted-proxy/internal-caller coupling.
  • PR discussion identified security risk: The provided review context includes a P1 review warning that unconditional localDirect acceptance can authenticate colocated reverse-proxy traffic without verified internal caller identity, matching current main's fail-closed implementation and docs. (src/gateway/auth.ts:401, f45ff858edd1)

So I’m closing this here and keeping the remaining discussion on the canonical linked item.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against 6cd047e7c270.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant