#22110: fix(tools): prefer loopback for internal tool-to-gateway RPC calls
agents
size: XS
Cluster:
Gateway Resilience and Configuration
When `gateway.bind` is `lan` or `tailnet`, internal tool calls (sessions_list, node.list, etc.) resolve to the LAN/tailnet IP instead of `127.0.0.1`. The CWE-319 security check (added in v2026.2.14) then blocks these as insecure plaintext connections, even though they're in-process with zero interception risk.
This breaks all agent tool calls in Docker containers with `bind: "lan"`.
**Root cause:** `resolveGatewayOptions()` left the URL undefined, deferring to `buildGatewayConnectionDetails()` which picks the bind-mode address. For internal calls, loopback is always correct since the gateway listens on `0.0.0.0` (which includes `127.0.0.1`).
**Fix:** `resolveGatewayOptions()` now resolves to `ws(s)://127.0.0.1:<port>` for local mode. Remote mode still defers to `callGateway` for remote URL resolution.
**Tests:**
- Updated existing test: now expects loopback URL instead of undefined
- Added test: remote mode still leaves URL undefined for remote resolution
- All 7 tests pass
Fixes #22104.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed internal tool-to-gateway RPC calls that were incorrectly resolving to LAN/tailnet IPs instead of loopback when `gateway.bind` is set to `lan` or `tailnet`, causing the CWE-319 security check to block them as insecure plaintext connections.
- Modified `resolveGatewayOptions()` in `gateway.ts:89-117` to explicitly resolve to `ws(s)://127.0.0.1:<port>` for local mode (respects TLS config)
- Remote mode still leaves URL undefined for proper remote resolution by `callGateway`
- Updated test to verify loopback URL resolution for local mode
- Added test coverage for remote mode behavior
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is targeted, well-tested, and correctly addresses the root cause. The loopback resolution is only applied to local mode (non-remote), which is the correct behavior. The CWE-319 check will now pass for internal calls since loopback is always secure. Remote mode still defers to `callGateway` as before.
- No files require special attention
<sub>Last reviewed commit: f0e2b98</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22056: fix(gateway): use loopback for self-connections regardless of bind ...
by usedhonda · 2026-02-20
89.3%
#21436: fix(gateway): plaintext ws:// blocked for Docker bind=lan (SECURITY...
by xinhuagu · 2026-02-19
85.1%
#19026: fix(gateway): use loopback for local CLI-to-gateway connections
by Phineas1500 · 2026-02-17
85.1%
#22804: fix: prioritize loopback for internal gateway calls (issue #22706)
by ambicuity · 2026-02-21
84.8%
#19437: Gateway: respect custom bind host for local health/RPC target resol...
by frudas24 · 2026-02-17
82.8%
#14564: fix(gateway): crashes on startup when tailscale meets non-loopback ...
by yinghaosang · 2026-02-12
81.7%
#21233: docs: clarify bind=lan non-loopback access requires wss or tunnel (...
by saurabhchopade · 2026-02-19
81.1%
#21741: fix(gateway): allow plaintext ws:// for Docker/private network addr...
by Joe3112 · 2026-02-20
80.6%
#16300: fix(tui): respect gateway bind mode in TUI connection
by cortexuvula · 2026-02-14
80.4%
#21772: [Bug]: Allow ws:// to Tailscale CGNAT addresses
by AIflow-Labs · 2026-02-20
80.2%