#21186: fix(gateway): strict loopback guard for Control UI (v2)
app: web-ui
gateway
size: M
## Summary
Implements a strict loopback guard for the Control UI to prevent accidental exposure when the gateway is bound to non-localhost interfaces.
This PR supersedes #21170, fixing a critical regression where the guard was applied to *all* traffic.
## Changes
- **NEW**: `src/gateway/control-ui-loopback-guard.ts`: Middleware to check remote address.
- **NEW**: `src/gateway/control-ui-loopback-guard.test.ts`: Unit tests for guard and path matching.
- **MODIFY**: `src/gateway/server-http.ts`: Apply guard *only* to Control UI routes using `isControlUiRequest`.
- **MODIFY**: `src/gateway/control-ui.ts`: Export `isControlUiRequest` helper.
## Fix Details
In PR #21170, the guard was applied unconditionally inside the `if (controlUiEnabled)` block, which (due to placement) affected all requests falling through to that point. This PR uses `isControlUiRequest` to ensure only actual Control UI traffic is checked.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes a critical regression from PR #21170 where the loopback guard was applied to ALL gateway traffic instead of just Control UI routes. This PR correctly scopes the guard by using `isControlUiRequest()` to check if the request targets Control UI paths before applying the security check.
**Key changes:**
- Adds `isControlUiRequest()` helper function to identify Control UI requests (avatars and UI routes)
- Guard now only runs for actual Control UI traffic, not for `/api/hooks`, OpenAI, Slack, or other endpoints
- Maintains proper request handler ordering: hooks/OpenAI/Slack handlers run first, then Control UI guard
- Comprehensive test coverage for both guard behavior and path matching logic
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix correctly addresses the regression by scoping the guard to only Control UI requests. The implementation properly leverages the existing request handler order where hooks/OpenAI/Slack handlers execute before the Control UI block, preventing false positives. Test coverage is comprehensive.
- No files require special attention
<sub>Last reviewed commit: baf55cd</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#6590: Harden Debug UI defaults: loopback-only binding + warnings
by dinakars777 · 2026-02-01
81.7%
#21326: Security/UI: harden Control UI gatewayUrl URL overrides
by bmendonca3 · 2026-02-19
81.6%
#20089: fix(gateway): preserve control-ui scopes when dangerouslyDisableDev...
by vashkartik · 2026-02-18
80.8%
#21100: Security/Gateway: require explicit break-glass env for Control UI b...
by bmendonca3 · 2026-02-19
79.3%
#8402: fix(ui): bypass /api in Control UI handler
by LarHope · 2026-02-04
78.4%
#17753: fix: Control UI unusable over HTTP - missing scopes
by MisterGuy420 · 2026-02-16
78.3%
#13960: fix(ui): preserve structured config validation error details
by constansino · 2026-02-11
78.0%
#23364: Gateway: add risk-ack interlock for dangerous Control UI flags
by bmendonca3 · 2026-02-22
77.8%
#22109: fix(gateway): allow Control UI session patch/delete
by lc708 · 2026-02-20
77.2%
#23465: Gateway: strengthen Control UI security headers
by bmendonca3 · 2026-02-22
76.7%