#18441: feat(gateway): add localNetworks config for subnet-scoped auto-pairing
gateway
stale
size: S
trusted-contributor
Cluster:
Gateway Resilience and Configuration
## Summary
- Adds `gateway.localNetworks` config option that accepts CIDR ranges or exact IPs to treat as "local" for auto-pairing
- By default, only loopback addresses (127.0.0.0/8, ::1) are trusted — no change in behavior for existing users
- Operators running in Docker/Kubernetes opt-in to their specific bridge subnet instead of trusting all RFC1918 ranges
- Adds `isLocalNetworkAddress()` helper in `net.ts` using existing CIDR matching infrastructure
- Threads `localNetworks` through all `isLocalDirectRequest` and `authorizeGatewayConnect` call sites
Example config:
```json
{
"gateway": {
"localNetworks": ["172.17.0.0/16"]
}
}
```
This replaces the original approach (trusting all RFC1918 private ranges) after security review feedback from @HenryLoenwind — blindly treating all private addresses as "local" is dangerous in multi-tenant environments where untrusted guests share the same address space.
## Test plan
- [x] Unit tests for `isLocalNetworkAddress` covering CIDR matching, exact IPs, IPv4-mapped IPv6, empty/undefined config
- [ ] Verify auto-pairing works from Docker container when `localNetworks: ["172.17.0.0/16"]` is set
- [ ] Verify auto-pairing is rejected from private IPs when `localNetworks` is not configured (default behavior unchanged)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds a `gateway.localNetworks` config option that lets operators define specific CIDR ranges or IPs to treat as "local" for auto-pairing, replacing the earlier approach of blindly trusting all RFC1918 private ranges. This is a security-conscious design that defaults to loopback-only and requires explicit opt-in for container networking subnets (e.g., Docker bridge `172.17.0.0/16`).
- New `isLocalNetworkAddress()` helper in `net.ts` reuses existing `normalizeIp()` and `ipMatchesCIDR()` infrastructure — structurally identical to `isTrustedProxyAddress()`.
- `localNetworks` is consistently threaded through all `isLocalDirectRequest()` and `authorizeGatewayConnect()` call sites in `server-http.ts` and `message-handler.ts`.
- Good unit test coverage for CIDR matching, exact IPs, IPv4-mapped IPv6, and edge cases.
- Note: `handleToolsInvokeHttpRequest` does not pass `localNetworks` to `authorizeGatewayConnect`, but this only affects the Tailscale fallback path (not auth bypass), so the impact is minimal — worth considering for consistency in a follow-up.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge — it adds an opt-in security feature with safe defaults and follows existing patterns throughout.
- Score of 4 reflects a well-structured, security-conscious change that follows existing patterns (`trustedProxies`). Deducted 1 point because: (1) the `localNetworks` config is not threaded to `handleToolsInvokeHttpRequest`, creating a minor inconsistency, and (2) the manual integration test plan items are not yet verified (marked unchecked in the PR description). The code itself is correct and the default behavior is unchanged.
- `src/gateway/auth.ts` deserves closest review — it contains the core security logic change where `localNetworks` broadens the definition of a "local" request for auth bypass.
<sub>Last reviewed commit: 14cfad7</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22343: fix(gateway): treat private LAN hosts as local direct
by AIflow-Labs · 2026-02-21
81.7%
#21741: fix(gateway): allow plaintext ws:// for Docker/private network addr...
by Joe3112 · 2026-02-20
78.2%
#19026: fix(gateway): use loopback for local CLI-to-gateway connections
by Phineas1500 · 2026-02-17
78.0%
#21436: fix(gateway): plaintext ws:// blocked for Docker bind=lan (SECURITY...
by xinhuagu · 2026-02-19
77.9%
#22365: fix(gateway): auto-approve loopback scope upgrades
by AIflow-Labs · 2026-02-21
77.3%
#22712: fix(gateway): auto-approve all device pairing for localhost connect...
by NewdlDewdl · 2026-02-21
77.1%
#7654: feat(security): zero-trust localhost auth with DNS rebinding protec...
by joncode · 2026-02-03
77.0%
#21697: fix(gateway): unblock local spawn pairing and gated private-LAN ws
by rjuanluis · 2026-02-20
76.7%
#21772: [Bug]: Allow ws:// to Tailscale CGNAT addresses
by AIflow-Labs · 2026-02-20
76.7%
#19437: Gateway: respect custom bind host for local health/RPC target resol...
by frudas24 · 2026-02-17
76.6%