← Back to PRs

#5278: fix(browser): prevent DNS rebinding in extension relay HTTP endpoints

by webvijayi open 2026-01-31 08:22 View on GitHub →
## 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