-
-
Notifications
You must be signed in to change notification settings - Fork 69.1k
[Bug]: Browser control server vulnerable to DNS rebinding attacks #4949
Description
Summary
Severity: P0/Critical (Score: 115/150)
CWE: CWE-350 - Reliance on Reverse DNS Resolution for a Security-Critical Action
OWASP: A05:2021 - Security Misconfiguration
File: src/browser/server.ts:33
The browser control server binds to 127.0.0.1 but lacks Host header validation, making it vulnerable to DNS rebinding attacks. Combined with the evaluate endpoint (#4950), this allows remote arbitrary JavaScript execution in controlled browser tabs.
Why this is critical: DNS rebinding turns a "localhost-only" server into a remotely exploitable one. The attack requires only that a victim visits a malicious website while the gateway is running. The attacker's page initially resolves to their server, then rebinds DNS to 127.0.0.1 after the browser caches the connection. All subsequent requests go to the victim's localhost but with the attacker's origin. This is a well-known attack class with proven exploits against development servers, IDEs, and local services.
Triage Assessment
| Factor | Value | Score |
|---|---|---|
| Reachability | Requires victim to visit malicious site | 25/40 |
| Impact | Remote code execution via evaluate endpoint | 45/50 |
| Exploitability | Requires DNS rebinding setup | 20/30 |
| Verification | file:line ✓, code ✓, attack steps ✓ | 25/30 |
| Total | — | 115/150 |
Steps to reproduce
- Start the gateway with browser control enabled
- Host a malicious website that:
- Initially resolves to attacker's IP
- After TTL expires, rebinds DNS to 127.0.0.1
- Have victim visit malicious site
- After DNS rebind, site makes POST to
http://malicious.com:PORT/actwith{kind: "evaluate", fn: "malicious code"} - JavaScript executes in victim's browser-controlled tabs
Expected behavior
The browser control server should validate the Host header to reject requests from rebinding attacks, or require authentication tokens.
Actual behavior
The server accepts requests from any origin as long as they reach 127.0.0.1, enabling DNS rebinding bypass.
Affected code location:
Browser Server (src/browser/server.ts:33):
const server = await new Promise<Server>((resolve, reject) => {
const s = app.listen(port, "127.0.0.1", () => resolve(s));
s.once("error", reject);
});
// No Host header validation
// No authentication mechanismEnvironment
- Version: latest (main branch)
- OS: Any
- Install method: Any
Impact
- Remote code execution: Attacker can execute arbitrary JS in browser tabs
- Credential theft: Access cookies, localStorage of controlled pages
- Session hijacking: Impersonate user on any site open in controlled browser
- Network pivoting: Use browser as proxy to internal network
Recommended fix
Add Host header validation:
app.use((req, res, next) => {
const host = req.headers.host;
const allowedHosts = ['localhost', '127.0.0.1', `localhost:${port}`, `127.0.0.1:${port}`];
if (!host || !allowedHosts.some(h => host === h || host.startsWith(h + ':'))) {
res.status(403).json({ error: 'Invalid Host header - possible DNS rebinding attack' });
return;
}
next();
});Or require authentication token:
const BROWSER_CONTROL_TOKEN = process.env.BROWSER_CONTROL_TOKEN || crypto.randomUUID();
app.use((req, res, next) => {
if (req.headers['x-browser-control-token'] !== BROWSER_CONTROL_TOKEN) {
res.status(401).json({ error: 'Invalid or missing authentication token' });
return;
}
next();
});