#5278: fix(browser): prevent DNS rebinding in extension relay HTTP endpoints
Cluster:
Chrome Extension Enhancements
## Summary
Fixes #5253
**Severity:** P0/Critical (Score: 130/150)
**CWE:** [CWE-350](https://cwe.mitre.org/data/definitions/350.html) - Reliance on Reverse DNS Resolution for a Security-Critical Action
**OWASP:** [A01:2021](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) - Broken Access Control
The Chrome extension relay's HTTP endpoints lacked Host header validation, allowing DNS rebinding attacks where a malicious webpage could enumerate, activate, and close browser tabs remotely.
## Attack Vector (Before Fix)
1. Attacker hosts webpage at `attacker.com`
2. DNS rebinding makes `attacker.com` resolve to `127.0.0.1`
3. Webpage requests `http://attacker.com:18800/json/list` → sees all open tabs
4. Webpage requests `/json/close/{targetId}` → closes victim's tabs
5. Webpage requests `/json/activate/{targetId}` → switches victim's focus
## Changes
### 1. New `isValidLoopbackHostHeader()` function
Validates Host header against loopback values with proper handling for:
- IPv4 with port: `127.0.0.1:8080`
- IPv6 with port: `[::1]:8080`
- Hostname: `localhost:8080`
### 2. Host header validation in HTTP handler
Rejects requests with non-loopback Host headers:
```
403 Forbidden: invalid Host header
```
### 3. Remote IP validation (defense in depth)
Added the same `isLoopbackAddress()` check that WebSocket upgrade already uses:
```
403 Forbidden: non-loopback remote address
```
### 4. Sanitized Host in responses
Uses known-good `info.host:info.port` instead of raw Host header to prevent response injection.
## Security Impact
| Attack | Before | After |
|--------|--------|-------|
| DNS rebinding | ✗ Vulnerable | ✓ Blocked |
| Tab enumeration | ✗ Exposed | ✓ Protected |
| Tab manipulation | ✗ Exploitable | ✓ Protected |
| Response injection | ✗ Possible | ✓ Prevented |
## Testing
To verify the fix:
```bash
# Should succeed (valid loopback Host)
curl -H "Host: localhost:18800" http://127.0.0.1:18800/json/list
# Should fail with 403 (DNS rebinding attempt)
curl -H "Host: attacker.com:18800" http://127.0.0.1:18800/json/list
```
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR hardens the Chrome extension relay’s HTTP endpoints against DNS rebinding by validating the `Host` header (loopback-only), checking the remote address is loopback for HTTP requests (matching the existing WebSocket upgrade check), and emitting a sanitized `ws://host:port` value in responses instead of reflecting the raw `Host` header.
The changes fit into `src/browser/extension-relay.ts` by adding a small Host-header validator and applying it early in the HTTP request handler, so all `/json/*` endpoints are protected before they can list/activate/close targets.
<h3>Confidence Score: 3/5</h3>
- This PR is close to safe to merge, but the Host validation semantics need a quick tightening check to ensure it doesn’t allow wildcard hosts or block legitimate local usage.
- The overall approach (Host header validation + loopback remote address check + avoiding Host reflection) addresses the described DNS rebinding vector. The main remaining concern is correctness of what’s considered an acceptable Host value: `isLoopbackHost()` currently treats `0.0.0.0`/`::` as acceptable, which may weaken the intended loopback-only restriction, and the Host parsing is slightly ad-hoc. If those semantics are confirmed/adjusted, risk is low.
- src/browser/extension-relay.ts
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16060: fix(browser): require relay auth token for /extension WebSocket and...
by coygeek · 2026-02-14
79.1%
#20688: fix(browser): allow extension reconnect when stale websocket linger...
by HOYALIM · 2026-02-19
78.6%
#7654: feat(security): zero-trust localhost auth with DNS rebinding protec...
by joncode · 2026-02-03
77.8%
#14197: fix(security): harden browser API auth, token comparisons, and hook...
by leecarollyn-gif · 2026-02-11
76.8%
#17588: fix(relay): survive WS disconnects and MV3 worker restarts
by Unayung · 2026-02-15
76.1%
#8228: fix(link-understanding): block private IPs and internal hostnames i...
by yubrew · 2026-02-03
76.0%
#17760: fix(browser): rewrite 0.0.0.0 and [::] wildcard addresses in CDP We...
by joeharouni · 2026-02-16
75.9%
#22252: fix(chrome-extension): connection validation and clarify relay port...
by krizpoon · 2026-02-20
75.5%
#19766: fix: Chrome relay extension auto-reattach after SPA navigation
by nishantkabra77 · 2026-02-18
75.4%
#13568: Fix browser (OpenClaw-managed) launch fail by binding remote debugg...
by singlag · 2026-02-10
75.3%