openclaw - ✅(Solved) Fix Browser cannot attach/use healthy local Brave CDP on hardened Debian 13 VPS [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#60804Fetched 2026-04-08 02:46:59
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
referenced ×4cross-referenced ×1

On a hardened Debian 13 VPS, OpenClaw browser automation fails even though Brave is running headless, exposes a valid CDP endpoint on localhost, and returns a valid webSocketDebuggerUrl.

OpenClaw reports the browser profile as not running, returns no tabs, and browser open fails with PortInUseError instead of attaching to the existing CDP browser.

This appears to be an OpenClaw Linux/VPS browser attach/runtime issue, not a missing-browser or broken-CDP issue.

Error Message

GatewayClientRequestError: Error: Chrome CDP websocket for profile "openclaw" is not reachable after start.

Root Cause

On a hardened Debian 13 VPS, OpenClaw browser automation fails even though Brave is running headless, exposes a valid CDP endpoint on localhost, and returns a valid webSocketDebuggerUrl.

OpenClaw reports the browser profile as not running, returns no tabs, and browser open fails with PortInUseError instead of attaching to the existing CDP browser.

This appears to be an OpenClaw Linux/VPS browser attach/runtime issue, not a missing-browser or broken-CDP issue.

Fix Action

Fixed

PR fix notes

PR #60833: fix(browser): SSRF policy blocks loopback CDP control-plane connections

Description (problem / solution / changelog)

Summary

  • Problem: browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: false blocks CDP control-plane reachability checks to 127.0.0.1, making local browser profiles report running: false and PortInUseError despite a healthy browser.
  • Why it matters: Users who set SSRF policy to protect against malicious navigation targets unintentionally break OpenClaw's own CDP management channel, making all browser commands fail.
  • What changed: Removed ssrfPolicy argument from isChromeReachable/isChromeCdpReady calls in CDP control-plane context (server-context.availability.ts, server-context.ts). Updated matching test assertions.
  • What did NOT change (scope boundary): Navigation-time SSRF enforcement in navigation-guard.ts is completely untouched. The SSRF policy still applies to browser navigation targets.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #60804
  • Related #45153, #57055, #49815, #49786
  • This PR fixes a bug or regression

Root Cause / Regression History (if applicable)

  • Root cause: resolveBrowserSsrFPolicy() with dangerouslyAllowPrivateNetwork: false produces {} (empty truthy object). This policy is passed to CDP control-plane checks (isChromeReachable, isChromeCdpReady), which call assertCdpEndpointAllowedshouldSkipPrivateNetworkChecks → returns falseassertAllowedHostOrIpOrThrow("127.0.0.1") → loopback is in BLOCKED_IPV4_SPECIAL_USE_RANGES → throws SsrFBlockedError, silently caught → returns false.
  • Missing detection / guardrail: No test covered the combination of dangerouslyAllowPrivateNetwork: false + loopback CDP endpoint.
  • Prior context: SSRF policy was added broadly to all CDP calls without distinguishing control-plane from navigation-plane.
  • Why this regressed now: Reported when a user configured dangerouslyAllowPrivateNetwork: false on a Debian VPS with local Brave CDP.
  • If unknown, what was ruled out: N/A — root cause is confirmed.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: server-context.ensure-browser-available.waits-for-cdp-ready.test.ts
  • Scenario the test should lock in: isChromeReachable and isChromeCdpReady are called without ssrfPolicy for control-plane checks.
  • Why this is the smallest reliable guardrail: Verifies the call-site contract without needing real network or browser.
  • Existing test that already covers this (if any): Updated the existing reuses a pre-existing loopback browser test to assert no ssrfPolicy arg.
  • If no new test is added, why not: The existing test was updated to enforce the new contract.

User-visible / Behavior Changes

  • browser status will correctly show running: true for healthy local CDP browsers when dangerouslyAllowPrivateNetwork: false is set.
  • browser tabs will work correctly instead of showing "No tabs".
  • browser open will attach to existing browser instead of throwing PortInUseError.

Diagram (if applicable)

Before:
[isChromeReachable(cdpUrl, timeout, ssrfPolicy:{})] -> assertCdpEndpointAllowed -> SsrFBlockedError -> false

After:
[isChromeReachable(cdpUrl, timeout)] -> assertCdpEndpointAllowed(no policy) -> skips SSRF check -> HTTP probe -> true/false

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No — same CDP HTTP/WS probes, just without SSRF gating on the control plane
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • Note: The CDP endpoint is an explicitly configured, trusted control channel. SSRF protection for browser navigation targets remains fully intact via navigation-guard.ts.

Repro + Verification

Environment

  • OS: Debian 13 VPS (reported); any OS with local CDP browser
  • Runtime/container: Node 22+
  • Model/provider: N/A
  • Integration/channel (if any): Browser tool
  • Relevant config (redacted): browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: false

Steps

  1. Configure browser.ssrfPolicy.dangerouslyAllowPrivateNetwork: false
  2. Start a local Brave/Chrome with CDP on 127.0.0.1:18800
  3. Run openclaw browser status

Expected

  • running: true, tabs listed

Actual (before fix)

  • running: false, tabCount: 0, PortInUseError on attach

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Test reuses a pre-existing loopback browser after an initial short probe miss failed before the fix (expected ssrfPolicy arg) and passes after (no ssrfPolicy arg in control-plane calls).

Human Verification (required)

  • Verified scenarios: All browser extension tests pass (pnpm test -- extensions/browser); navigation-guard tests pass independently; pnpm check clean.
  • Edge cases checked: Confirmed navigation-guard.ts SSRF enforcement is untouched via its own passing test suite (17 tests).
  • What you did not verify: Live end-to-end test with a real Brave CDP endpoint on Debian VPS (requires specific hardware setup from issue reporter).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: Reduced SSRF coverage for CDP control-plane connections.
    • Mitigation: CDP endpoints are explicitly configured trusted channels. Navigation-time SSRF enforcement (the actual protection surface) remains intact. The CDP endpoint address comes from user config, not from untrusted input.

Changed files

  • extensions/browser/src/browser/server-context.availability.ts (modified, +11/-2)
  • extensions/browser/src/browser/server-context.ensure-browser-available.waits-for-cdp-ready.test.ts (modified, +8/-7)
  • extensions/browser/src/browser/server-context.ts (modified, +1/-1)

Code Example

/usr/bin/brave-browser --headless=new --no-sandbox --disable-gpu \
  --remote-debugging-port=18800 \
  --user-data-dir=$HOME/.openclaw/browser/openclaw/user-data \
  about:blank

---

{
  "Browser": "Chrome/146.0.7680.178",
  "webSocketDebuggerUrl": "ws://127.0.0.1:18800/devtools/browser/..."
}

---

{
  "browser": {
    "executablePath": "/usr/bin/brave-browser",
    "headless": true,
    "noSandbox": true,
    "evaluateEnabled": false,
    "ssrfPolicy": {
      "dangerouslyAllowPrivateNetwork": false
    }
  }
}

---

{
  "browser": {
    "defaultProfile": "localcdp",
    "profiles": {
      "localcdp": {
        "cdpUrl": "ws://127.0.0.1:18800/devtools/browser/<id>",
        "color": "#00AA88"
      }
    }
  }
}

---

GatewayClientRequestError: Error: Chrome CDP websocket for profile "openclaw" is not reachable after start.

---

profile: localcdp
enabled: true
running: false
transport: cdp
cdpUrl: ws://127.0.0.1:18800/devtools/browser/...
browser: unknown

---

No tabs (browser closed or no targets).

---

GatewayClientRequestError: PortInUseError: Port 18800 is already in use.
RAW_BUFFERClick to expand / collapse

Summary

On a hardened Debian 13 VPS, OpenClaw browser automation fails even though Brave is running headless, exposes a valid CDP endpoint on localhost, and returns a valid webSocketDebuggerUrl.

OpenClaw reports the browser profile as not running, returns no tabs, and browser open fails with PortInUseError instead of attaching to the existing CDP browser.

This appears to be an OpenClaw Linux/VPS browser attach/runtime issue, not a missing-browser or broken-CDP issue.

Environment

  • OpenClaw: 2026.4.2
  • OS: Debian 13 (Trixie)
  • Host type: public VPS, hardened
  • Browser tested:
    • Debian Chromium (removed after testing)
    • Brave Browser 146.1.88.138
  • OpenClaw Gateway:
    • loopback-bound
    • token auth
  • Browser config used:
    • headless: true
    • noSandbox: true
    • evaluateEnabled: false
    • ssrfPolicy.dangerouslyAllowPrivateNetwork: false

What was verified

Browser binary/runtime is healthy

Brave runs successfully headless as a persistent user service:

/usr/bin/brave-browser --headless=new --no-sandbox --disable-gpu \
  --remote-debugging-port=18800 \
  --user-data-dir=$HOME/.openclaw/browser/openclaw/user-data \
  about:blank

Service stays up and 127.0.0.1:18800 listens correctly.

CDP endpoint is healthy

curl http://127.0.0.1:18800/json/version returns valid JSON including:

{
  "Browser": "Chrome/146.0.7680.178",
  "webSocketDebuggerUrl": "ws://127.0.0.1:18800/devtools/browser/..."
}

So CDP is live and reachable on localhost.

Config tested

Managed local browser path

{
  "browser": {
    "executablePath": "/usr/bin/brave-browser",
    "headless": true,
    "noSandbox": true,
    "evaluateEnabled": false,
    "ssrfPolicy": {
      "dangerouslyAllowPrivateNetwork": false
    }
  }
}

Explicit CDP profile path

Also tested with explicit WebSocket CDP profile and default profile switched to it:

{
  "browser": {
    "defaultProfile": "localcdp",
    "profiles": {
      "localcdp": {
        "cdpUrl": "ws://127.0.0.1:18800/devtools/browser/<id>",
        "color": "#00AA88"
      }
    }
  }
}

Observed failures

1. Managed launch path

openclaw browser start

returns:

GatewayClientRequestError: Error: Chrome CDP websocket for profile "openclaw" is not reachable after start.

2. Explicit CDP profile path

Even with a valid live websocket URL configured, OpenClaw still reports:

profile: localcdp
enabled: true
running: false
transport: cdp
cdpUrl: ws://127.0.0.1:18800/devtools/browser/...
browser: unknown

3. Tabs/status unusable

openclaw browser tabs returns:

No tabs (browser closed or no targets).

4. Open against existing CDP browser fails incorrectly

openclaw browser open https://example.com

returns:

GatewayClientRequestError: PortInUseError: Port 18800 is already in use.

This suggests OpenClaw is still trying to launch/manage rather than correctly attaching to and using the already-running CDP browser.

Why this seems like an OpenClaw bug

The following have already been ruled out:

  • browser missing
  • bad browser path
  • bad CDP port
  • bad localhost connectivity
  • bad CDP websocket URL
  • Chromium-only packaging issue
  • non-headless launch issue
  • missing noSandbox
  • transient ad hoc browser process instability

The strongest evidence is:

  • the browser is alive
  • CDP is alive
  • the websocket URL is valid
  • OpenClaw still refuses to mark it running or use it

Extra notes

  • This was first reproduced with Debian Chromium, then reproduced again after migrating to Brave.
  • Chromium install temporarily reintroduced Avahi/mDNS on the VPS; that was removed and is unrelated to the CDP failure.
  • Host firewall is not blocking localhost.
  • Public network exposure is irrelevant here; all CDP traffic is on 127.0.0.1.

Suspected area

Likely in OpenClaw’s Linux browser runtime/attach logic:

  • profile running-state detection
  • CDP websocket readiness check
  • attach-vs-launch behavior when cdpUrl is already configured
  • handling of existing port-occupied browser sessions

Minimal repro shape

  1. Debian 13 VPS
  2. Install Brave
  3. Configure OpenClaw browser:
    • headless
    • noSandbox
    • executablePath set to Brave
  4. Start Brave manually or via user systemd with:
    • --headless=new
    • --no-sandbox
    • --remote-debugging-port=18800
    • dedicated --user-data-dir
  5. Confirm curl http://127.0.0.1:18800/json/version works
  6. Set OpenClaw browser profile cdpUrl to the returned websocket URL
  7. Run:
    • openclaw browser status
    • openclaw browser tabs
    • openclaw browser open https://example.com
  8. Observe:
    • running: false
    • No tabs
    • PortInUseError

extent analysis

TL;DR

The most likely fix involves modifying OpenClaw's Linux browser runtime/attach logic to correctly handle existing CDP browser sessions and improve profile running-state detection.

Guidance

  1. Verify CDP Endpoint: Ensure the CDP endpoint is healthy and reachable by running curl http://127.0.0.1:18800/json/version and verifying the response includes a valid webSocketDebuggerUrl.
  2. Check OpenClaw Configuration: Review the OpenClaw browser configuration to ensure it matches the expected settings, including headless, noSandbox, and executablePath set to Brave.
  3. Investigate Profile Running-State Detection: Investigate how OpenClaw detects the running state of browser profiles and consider modifying this logic to correctly handle cases where the browser is already running.
  4. Handle Existing Port-Occupied Browser Sessions: Modify OpenClaw's attach-vs-launch behavior to handle cases where the CDP port is already occupied by an existing browser session.

Example

No code example is provided as the issue seems to be related to OpenClaw's internal logic and configuration.

Notes

The provided information suggests that the issue is specific to OpenClaw's Linux browser runtime/attach logic. Further investigation and modification of this logic may be necessary to resolve the issue.

Recommendation

Apply a workaround by modifying OpenClaw's configuration and logic to correctly handle existing CDP browser sessions and improve profile running-state detection. This may involve customizing the OpenClaw setup to better suit the specific use case.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING