#23690: fix(gateway): subagent sessions fail with pairing required on loopback (#23661)
gateway
size: S
trusted-contributor
Cluster:
Device Pairing and Gateway Fixes
## Summary
Subagent sessions can't connect to loopback gateways — they hit "pairing required" (1008) on scope upgrades. The `requirePairing` function only auto-approves "not-paired" reasons for local clients, so scope-upgrade requests get rejected even on 127.0.0.1.
Closes #23661
lobster-biscuit
## Root Cause
`requirePairing` in `message-handler.ts` sets `silent: isLocalClient && reason === "not-paired"`. When a subagent calls `callGateway({ method: "agent" })`, it goes through `callGatewayLeastPrivilege` which requests `["operator.write"]`. If the device was paired before scopes existed (empty `pairedScopes`), the handler hits the `pairedScopes.length === 0` branch and calls `requirePairing("scope-upgrade")` — which isn't auto-approved on loopback.
This was introduced by `0bda0202fd` (security hardening, 2026-02-19) which tightened `silent: isLocalClient` to `silent: isLocalClient && reason === "not-paired"`.
## Changes
- Before: only "not-paired" pairing requests are auto-approved on loopback; scope upgrades require manual approval (which never appears in `nodes pending`)
- After: both "not-paired" and "scope-upgrade" are auto-approved on loopback; role upgrades still require explicit approval
## Tests
- Updated `requires pairing for scope upgrades` — now expects auto-approval on loopback
- Updated `rejects scope escalation from legacy paired metadata` → renamed to `auto-approves scope escalation from legacy paired metadata on loopback`
- Added `auto-approves scope upgrade on loopback for legacy paired device` — pairs with `operator.read`, strips scopes, reconnects requesting `operator.write`, expects success
- All 37 tests in `server.auth.test.ts` pass
- `pnpm build && pnpm check` pass
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a regression where subagent sessions connecting to loopback gateways would fail with "pairing required" (1008) when requesting scope upgrades. The fix changes the auto-approval logic from only allowing `not-paired` requests to allowing both `not-paired` and `scope-upgrade` requests on loopback connections (127.0.0.1).
**Key changes:**
- Modified `message-handler.ts:641` to change `silent: isLocalClient && reason === "not-paired"` to `silent: isLocalClient && reason !== "role-upgrade"`
- Updated existing tests to expect auto-approval for scope upgrades on loopback
- Added new test case for legacy paired devices requesting scope upgrades
**Security posture:** The change relaxes security only for loopback connections. Role upgrades still require explicit approval even on loopback, maintaining the important security boundary. Scope upgrades within the same role are now auto-approved on loopback, which is appropriate for local trusted connections and fixes the subagent connectivity issue.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with low risk - it fixes a legitimate regression while maintaining security boundaries
- The change is well-targeted and fixes a specific regression introduced by commit `0bda0202fd`. The security relaxation is limited to loopback connections only, which is appropriate. Role upgrades still require manual approval, maintaining the critical security boundary. Test coverage is comprehensive with three test cases updated/added to verify the behavior. However, the score is 4 rather than 5 because this is a security-sensitive change that relaxes access controls, and while the change appears correct, any modification to authentication/authorization logic warrants extra scrutiny in production.
- No files require special attention - both files have appropriate changes with good test coverage
<sub>Last reviewed commit: 1a9d19a</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#23708: fix(gateway): auto-approve scope upgrades for loopback clients
by widingmarcus-cyber · 2026-02-22
93.6%
#22365: fix(gateway): auto-approve loopback scope upgrades
by AIflow-Labs · 2026-02-21
89.6%
#17425: fix(gateway): auto-approve scope/role upgrades for already-paired d...
by sauerdaniel · 2026-02-15
88.1%
#22253: fix: auto-approve local loopback pairing for role/scope upgrades
by cjpraia · 2026-02-20
88.1%
#22280: fix(gateway): silently auto-approve local paired-device scope upgrades
by abhishekp76 · 2026-02-21
86.1%
#22712: fix(gateway): auto-approve all device pairing for localhost connect...
by NewdlDewdl · 2026-02-21
86.0%
#21664: fix(gateway): require re-pairing for legacy devices that lack scope...
by AI-Reviewer-QS · 2026-02-20
85.5%
#22587: fix(gateway): silently auto-approve local paired-device scope upgrades
by abhishekp76 · 2026-02-21
84.7%
#23039: fix: subagent announce fails with pairing required due to missing o...
by ascott · 2026-02-21
84.4%
#21697: fix(gateway): unblock local spawn pairing and gated private-LAN ws
by rjuanluis · 2026-02-20
84.2%