#23708: fix(gateway): auto-approve scope upgrades for loopback clients
gateway
size: XS
trusted-contributor
Cluster:
Device Pairing and Gateway Fixes
## Summary
Fixes subagent sessions failing with `pairing required` error when spawned on a loopback gateway.
## Problem
When a device previously paired with a narrower scope (e.g. `operator.read`) reconnects from localhost requesting broader scopes (e.g. `operator.admin`), the gateway triggers the full pairing flow — requiring manual approval even though the client is local and trusted.
This breaks subagent sessions because `sessions.patch` requires `operator.admin` scope, but the initial `gateway-client` connection was paired with only `operator.read`. The scope upgrade triggers `requirePairing("scope-upgrade")` which rejects the connection with `1008: pairing required`.
## Root Cause
The silent auto-approve check in `message-handler.ts` only applied to `not-paired` reason:
```ts
silent: isLocalClient && reason === "not-paired",
```
Scope upgrades from local clients were treated identically to remote clients — requiring explicit manual approval.
## Fix
Extend the silent auto-approve to include `scope-upgrade` for local clients:
```ts
silent: isLocalClient && (reason === "not-paired" || reason === "scope-upgrade"),
```
**Role upgrades** (e.g. `operator` → `node`) still require explicit approval regardless of client location, preserving the security boundary between different trust levels.
## Testing
- Updated existing `requires pairing for scope upgrades` test → `auto-approves scope upgrades for local clients`
- Updated legacy metadata test to verify auto-approval works for devices missing scope metadata
- All 36 auth tests pass
Fixes #23661
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Extends silent auto-approval for loopback clients from just initial pairing (`not-paired`) to also include scope upgrades (`scope-upgrade`). This fixes subagent sessions that previously failed with "pairing required" errors when escalating from `operator.read` to `operator.admin`.
The change modifies the condition in `message-handler.ts:641` from:
```ts
silent: isLocalClient && reason === "not-paired"
```
to:
```ts
silent: isLocalClient && (reason === "not-paired" || reason === "scope-upgrade")
```
Key security properties preserved:
- Only applies to loopback clients verified by `isLocalDirectRequest()` (checks IP is loopback AND host is localhost/127.0.0.1/::1/ts.net AND no untrusted proxy headers)
- Role upgrades (`operator` → `node`) still require manual approval regardless of client location
- Scope validation still enforced through `roleScopesAllow()` before pairing
Tests updated to verify auto-approval works for both normal scope upgrades and legacy metadata (devices paired before scopes field existed).
<h3>Confidence Score: 5/5</h3>
- Safe to merge - targeted fix with preserved security boundaries
- The change is minimal (one line), well-tested (36 auth tests pass), and maintains strong security invariants. The `isLocalClient` check requires both loopback IP AND local hostname AND absence of untrusted proxy headers. Role upgrades still require manual approval, preserving the security boundary between operator and node roles. The fix directly addresses the documented issue without introducing new attack surface.
- No files require special attention
<sub>Last reviewed commit: 41a0aff</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#23690: fix(gateway): subagent sessions fail with pairing required on loopb...
by yinghaosang · 2026-02-22
93.6%
#22365: fix(gateway): auto-approve loopback scope upgrades
by AIflow-Labs · 2026-02-21
91.0%
#22280: fix(gateway): silently auto-approve local paired-device scope upgrades
by abhishekp76 · 2026-02-21
89.4%
#22587: fix(gateway): silently auto-approve local paired-device scope upgrades
by abhishekp76 · 2026-02-21
89.3%
#22838: fix(gateway): auto-approve loopback pairing for scope/role upgrades
by GodsBoy · 2026-02-21
89.1%
#17425: fix(gateway): auto-approve scope/role upgrades for already-paired d...
by sauerdaniel · 2026-02-15
89.0%
#22712: fix(gateway): auto-approve all device pairing for localhost connect...
by NewdlDewdl · 2026-02-21
88.4%
#22253: fix: auto-approve local loopback pairing for role/scope upgrades
by cjpraia · 2026-02-20
88.2%
#22794: fix: allow local clients to auto-pair without manual approval
by Matrix-Meta · 2026-02-21
85.2%
#21666: fix(gateway): restrict auto-paired device scopes to safe defaults
by AI-Reviewer-QS · 2026-02-20
84.8%