Skip to content

[Bug]: Arbitrary JavaScript execution via browser evaluate endpoint when enabled #4950

@coygeek

Description

@coygeek

Summary

Severity: P0/Critical (Score: 130/150)
CWE: CWE-94 - Improper Control of Generation of Code ('Code Injection')
OWASP: A03:2021 - Injection
File: src/browser/pw-tools-core.interactions.ts:227-257

When evaluateEnabled=true, the browser control server accepts arbitrary JavaScript via the /act endpoint and executes it directly via eval() in the browser context with no sanitization, sandboxing, or scope restriction.

Why this is critical: This is arbitrary code execution in the browser context. While gated by a config flag, once enabled there are zero controls—any JavaScript can read cookies, access localStorage, manipulate the DOM, make fetch requests with the page's credentials, or exfiltrate data. Combined with DNS rebinding (#4949), this becomes remotely exploitable. The eval() pattern is the textbook example of dangerous code injection.

Triage Assessment

Factor Value Score
Reachability Config-dependent (requires evaluateEnabled) 25/40
Impact Arbitrary code execution in browser 50/50
Exploitability Single POST request 30/30
Verification file:line ✓, code ✓, attack steps ✓ 25/30
Total 130/150

Steps to reproduce

  1. Configure with evaluateEnabled: true
  2. POST to /act with body: {kind: "evaluate", fn: "document.cookie"}
  3. Observe arbitrary JavaScript execution in the browser context

Expected behavior

Even when evaluate is enabled, there should be:

  • Sandboxing or scope restrictions
  • Input validation against known-safe patterns
  • Audit logging of evaluated code
  • Rate limiting

Actual behavior

The fnText parameter is passed directly to eval() with no restrictions:

Affected code location:

Evaluate Implementation (src/browser/pw-tools-core.interactions.ts:227-257):

const browserEvaluator = new Function(
  "fnBody",
  `
  "use strict";
  try {
    var candidate = eval("(" + fnBody + ")");
    return typeof candidate === "function" ? candidate() : candidate;
  } catch (err) {
    // ...
  }
`
);

Environment

  • Version: latest (main branch)
  • OS: Any
  • Install method: Any

Impact

  • Session hijacking: Read cookies, localStorage, sessionStorage
  • Credential theft: Capture form inputs, access saved passwords
  • Data exfiltration: Read page content, make authenticated requests
  • Malware delivery: Inject scripts, redirect users
  • Lateral movement: Access internal network resources via browser

Recommended fix

  1. Remove evaluate functionality entirely, or
  2. Implement a strict allowlist of safe operations:
const ALLOWED_EVALUATIONS = {
  'getInnerText': (selector: string) => document.querySelector(selector)?.innerText,
  'getValue': (selector: string) => (document.querySelector(selector) as HTMLInputElement)?.value,
  // ... other specific, safe operations
};

// Reject arbitrary code, only allow predefined operations
if (!ALLOWED_EVALUATIONS[operation]) {
  throw new Error(`Unsupported evaluation: ${operation}`);
}

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