#22381: Security/Gateway: block cross-origin silent auto-pairing in auth mode none
gateway
size: S
Cluster:
Device Pairing and Gateway Fixes
## Summary
- Problem: in gateway WS connect flow, `auth.mode=none` allowed local unpaired devices to be silently auto-approved based on loopback locality alone.
- Why it matters: browser pages can initiate loopback WebSocket requests; untrusted cross-origin requests should not receive silent pairing approval.
- What changed: gate silent auto-pairing on trusted browser origin (`checkBrowserOrigin`) in addition to existing local-direct checks.
- What did NOT change (scope boundary): no changes to auth mode resolution, role/scope policy, or non-pairing gateway method authorization.
## Change Type (select all)
- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Docs
- [x] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [x] Gateway / orchestration
- [ ] Skills / tool execution
- [x] Auth / tokens
- [ ] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Closes #
- Related #21618
## User-visible / Behavior Changes
- In `gateway.auth.mode=none`, cross-origin browser WS connects no longer get silent device auto-pair approval; they now receive normal `pairing required` flow.
## Security Impact (required)
- New permissions/capabilities? (`No`)
- Secrets/tokens handling changed? (`No`)
- New/changed network calls? (`No`)
- Command/tool execution surface changed? (`No`)
- Data access scope changed? (`No`)
- If any `Yes`, explain risk + mitigation:
## Repro + Verification
### Environment
- OS: macOS
- Runtime/container: Node 22, pnpm
- Model/provider: N/A
- Integration/channel (if any): Gateway WS
- Relevant config (redacted): `gateway.auth.mode=none`
### Steps
1. Start gateway with `gateway.auth.mode=none`.
2. Open WS with non-loopback Origin (`https://evil.example`) and send `connect` with fresh device identity.
3. Observe handshake result.
### Expected
- Cross-origin browser request should not silently auto-pair; handshake should require explicit pairing approval.
### Actual
- After fix, handshake returns `pairing required` (regression test added).
## Evidence
- [x] Failing test/log before + passing after
- [ ] Trace/log snippets
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)
## Human Verification (required)
What you personally verified (not just CI), and how:
- Verified scenarios:
- Targeted e2e: `does not silently auto-approve cross-origin browser pairing in mode none` passes.
- Existing mode-none loopback connect test remains passing.
- Edge cases checked:
- Silent pairing path still allowed for trusted/local origin behavior.
- What you did **not** verify:
- Full matrix of every browser client ID + origin combination beyond targeted e2e coverage.
## Compatibility / Migration
- Backward compatible? (`Yes`)
- Config/env changes? (`No`)
- Migration needed? (`No`)
- If yes, exact upgrade steps:
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly:
- Revert commit `889525b8e`.
- Files/config to restore:
- `src/gateway/server/ws-connection/message-handler.ts`
- `src/gateway/server.auth.e2e.test.ts`
- Known bad symptoms reviewers should watch for:
- Unexpected pairing prompts for legitimate local-browser flows.
## Risks and Mitigations
- Risk:
- Overly strict origin trust could reduce convenience for some local browser workflows.
- Mitigation:
- Scope limited to silent auto-approval path; non-silent pairing fallback remains available.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Prevented cross-origin browser pages from silently auto-pairing in `gateway.auth.mode=none` by gating silent approval on trusted browser origin check. The fix adds `browserOriginTrustedForLocal` check to the silent pairing condition while preserving loopback auto-pairing for non-browser local clients (which don't send Origin headers). Test coverage includes regression test for cross-origin rejection and verification that legitimate loopback flows continue working.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is narrowly scoped, addresses a clear security vulnerability, includes targeted regression tests, and preserves existing legitimate flows. The logic is sound: browsers send Origin headers which can be validated, while non-browser clients don't send them and are treated as trusted by default.
- No files require special attention
<sub>Last reviewed commit: 889525b</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22712: fix(gateway): auto-approve all device pairing for localhost connect...
by NewdlDewdl · 2026-02-21
83.0%
#17425: fix(gateway): auto-approve scope/role upgrades for already-paired d...
by sauerdaniel · 2026-02-15
82.7%
#22280: fix(gateway): silently auto-approve local paired-device scope upgrades
by abhishekp76 · 2026-02-21
82.2%
#22365: fix(gateway): auto-approve loopback scope upgrades
by AIflow-Labs · 2026-02-21
81.7%
#23690: fix(gateway): subagent sessions fail with pairing required on loopb...
by yinghaosang · 2026-02-22
81.4%
#23708: fix(gateway): auto-approve scope upgrades for loopback clients
by widingmarcus-cyber · 2026-02-22
81.1%
#19088: fix(gateway): allow startup with unset mode and fix pairing for local…
by mdanassaif · 2026-02-17
81.0%
#23361: Gateway: reject scope assertions without identity binding
by bmendonca3 · 2026-02-22
80.9%
#17705: fix(gateway): allow trusted-proxy auth to bypass device-pairing gates
by dashed · 2026-02-16
80.7%
#16310: fix(ws-connection): skip device pairing when client authenticates w...
by nawinsharma · 2026-02-14
80.7%