Skip to content

fix(chrome,edge): enforce configured token on page CDP WebSocket route - #5512

Draft
artiom wants to merge 1 commit into
mainfrom
fix/page-cdp-websocket-token-auth
Draft

fix(chrome,edge): enforce configured token on page CDP WebSocket route#5512
artiom wants to merge 1 commit into
mainfrom
fix/page-cdp-websocket-token-auth

Conversation

@artiom

@artiom artiom commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Problem

When the service is started with a TOKEN, the chrome and edge page CDP WebSocket routes did not enforce it. Both routes overrode the base route with auth = false, so the server's token check was skipped for /devtools/page/* upgrades.

Effect on a token-protected instance:

  • A client with no token could open a page target and run arbitrary CDP commands (e.g. Runtime.evaluate, Page.navigate).
  • chromium and the base route were unaffected — they returned 401 for the same request.

The auth = false override was originally added so the token-less devtoolsFrontendUrl inspector link kept working; the fix preserves that link while restoring auth.

Changes

  • Remove the auth = false overrides on the chrome and edge page WebSocket routes so both inherit the base route's auth = true. Page CDP auth is now consistent across chrome, edge, chromium, and multi.
  • Keep DevTools links usable under auth: thread the requesting token into the generated devtoolsFrontendUrl for /json/list, /json/new, and /sessions, via new makeExternalWebSocketURL / makeDevtoolsFrontendURL helpers. webSocketDebuggerUrl continues to exclude the token by design (clients add their own authorization when connecting).
    • This also fixes a pre-existing issue where /json/list built its inspector link from Chrome's own (Google-hosted) frontend with the nested WebSocket pointing at the internal browser port — not reachable by an external client. It is now self-hosted and externally routable, with sub-path prefixes preserved.
  • Redact tokens from request-URL logs (top-level token, and tokens nested in DevTools ws/wss params) without mutating the request used for auth/routing. Document devtoolsFrontendUrl as credential-bearing.
  • Non-vacuous regression tests for chrome and edge: the previous "rejects unauthorized" tests asserted only inside a catch block, so they passed without executing whenever the connection was wrongly accepted. New tests fail if a token-less page connection is accepted while a token is configured, and confirm the authorized connection still runs CDP. Added coverage for the token-carrying DevTools URLs (/json/list, /json/new, /sessions) and the URL helpers.

Verification

Built and run locally in Docker (chromium; chrome and edge validated on linux/amd64):

  • Token-less page WebSocket connection → 401 on chrome, edge, and chromium (previously accepted on chrome/edge).
  • Authorized page WebSocket connection → connects and executes CDP.
  • devtoolsFrontendUrl from /json/new and /json/list loads the inspector asset and connects with the embedded token; the same target with the token stripped is refused.
  • With no TOKEN configured, behavior is unchanged (page connections and /json/list work without a token).

Behavior change (worth a release note)

On token-protected chrome/edge/multi, a client that connects to a raw page target (/devtools/page/*) without a token now receives 401. This matches chromium's existing behavior. webSocketDebuggerUrl has always excluded the token, so authenticated clients must include their authorization when connecting to it.

🤖 Generated with Claude Code


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • DevTools and WebSocket URLs now work correctly with external addresses and authentication tokens.
    • Session and browser-list responses include token-authorized connection URLs when required.
    • Special characters in authentication tokens are safely encoded.
  • Security

    • Sensitive tokens are redacted from request and access logs.
    • Unauthorized page WebSocket connections are consistently rejected.
  • Documentation

    • Updated API guidance to identify credential-bearing DevTools URLs and recommend redacting query strings.

The chrome and edge page WebSocket routes set `auth = false`, so a
configured TOKEN was not enforced on `/devtools/page/*` connections. A
token-less client could open a page target and issue arbitrary CDP
commands, while chromium (and the base route) correctly returned 401.

Remove the `auth = false` overrides so chrome and edge inherit the base
route's `auth = true`, making page CDP auth consistent across chrome,
edge, chromium, and multi.

To keep DevTools inspector links usable once the route enforces auth,
thread the requesting token into the generated `devtoolsFrontendUrl`
for `/json/list`, `/json/new`, and `/sessions` via new
`makeExternalWebSocketURL` / `makeDevtoolsFrontendURL` helpers. The
`webSocketDebuggerUrl` continues to exclude the token by design, so
authenticated clients add their own authorization when connecting.

Redact top-level and nested `ws`/`wss` tokens from request-URL logs and
document the `devtoolsFrontendUrl` field as credential-bearing.

Add non-vacuous regression tests for chrome and edge: the previous
"rejects unauthorized" assertions lived only inside `catch`, so they
passed without executing whenever the connection was wrongly accepted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Token-aware URL helpers now support external WebSocket and DevTools URL construction, JSON endpoints propagate request tokens, and server logs redact credential-bearing query parameters. Chrome and Edge page WebSocket tests explicitly verify unauthorized rejection and authorized CDP access.

Changes

Token-aware DevTools URLs

Layer / File(s) Summary
URL construction and redaction helpers
src/utils.ts, src/utils.spec.ts, src/types.ts
Adds external WebSocket and DevTools URL builders, nested/top-level token redaction, related tests, and credential-bearing devtoolsFrontendUrl documentation.
Browser payload URL rewriting
src/browsers/index.ts
Propagates optional tokens through JSON list and session generation, rewriting debugger and DevTools URLs with shared helpers.
JSON endpoint token propagation
src/shared/json-*.http.ts, src/routes/management/http/sessions.get.ts, src/routes/chromium/tests/*
Extracts request tokens for /json/list, /json/new, and /sessions, constructs authorized nested URLs, and validates encoding and external routing.
Request logging redaction
src/server.ts, src/routes/chromium/tests/websocket.spec.ts
Formats HTTP and WebSocket request URLs before logging and verifies nested credentials are absent from captured logs.
Page WebSocket authentication validation
src/routes/chrome/ws/page.ts, src/routes/edge/ws/page.ts, src/routes/{chrome,edge}/tests/page-websocket.spec.ts
Removes explicit authentication disabling from page routes and verifies tokenless rejection with tokenized CDP success.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant JSONRoute
  participant BrowserManager
  participant URLHelpers
  Client->>JSONRoute: request JSON endpoint with token
  JSONRoute->>BrowserManager: pass extracted token
  BrowserManager->>URLHelpers: build external WebSocket and DevTools URLs
  URLHelpers-->>BrowserManager: return rewritten URLs
  BrowserManager-->>JSONRoute: return JSON payload
  JSONRoute-->>Client: send token-aware payload
Loading

Suggested reviewers: joelgriffith

Poem

A rabbit hops through URLs bright,
Tucks tokens in nested links just right.
Logs lose secrets in the snow,
WebSockets guard the paths they know.
“Hop hooray!” the payloads sing.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the core change: enforcing configured token auth on Chrome and Edge page CDP WebSocket routes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/page-cdp-websocket-token-auth

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/browsers/index.ts (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the repeated DevTools inspector base-URL construction into a shared helper. The same 4-line pattern (new URL(externalAddress) + path.posix.join(pathname, '/devtools/inspector.html')) is copy-pasted in three places; a shared helper alongside makeExternalWebSocketURL/makeDevtoolsFrontendURL in src/utils.ts (e.g. makeDevtoolsInspectorURL(externalAddress: string): URL) would remove the duplication and prevent the three sites from drifting if the inspector path ever changes.

  • src/browsers/index.ts#L331-335: replace the inline devtoolsFrontendURL construction in getJSONList with the shared helper.
  • src/browsers/index.ts#L406-410: replace the inline frontendURL construction in generateSessionJson with the shared helper.
  • src/shared/json-new.http.ts#L65-69: replace the inline frontendURL construction in the /json/new handler with the shared helper.
♻️ Proposed helper
+export const makeDevtoolsInspectorURL = (externalAddress: string): URL => {
+  const frontendURL = new URL(externalAddress);
+  frontendURL.pathname = path.posix.join(
+    frontendURL.pathname,
+    '/devtools/inspector.html',
+  );
+  return frontendURL;
+};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/browsers/index.ts` at line 1, Extract the repeated DevTools inspector URL
construction into a shared makeDevtoolsInspectorURL helper alongside
makeExternalWebSocketURL and makeDevtoolsFrontendURL in src/utils.ts. Update
getJSONList, generateSessionJson, and the /json/new handler in json-new.http.ts
to use this helper, preserving the existing URL and inspector path behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/browsers/index.ts`:
- Line 1: Extract the repeated DevTools inspector URL construction into a shared
makeDevtoolsInspectorURL helper alongside makeExternalWebSocketURL and
makeDevtoolsFrontendURL in src/utils.ts. Update getJSONList,
generateSessionJson, and the /json/new handler in json-new.http.ts to use this
helper, preserving the existing URL and inspector path behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58665033-44e1-413a-82ba-5fbab270bd42

📥 Commits

Reviewing files that changed from the base of the PR and between fc39d5e and 530038d.

📒 Files selected for processing (14)
  • src/browsers/index.ts
  • src/routes/chrome/tests/page-websocket.spec.ts
  • src/routes/chrome/ws/page.ts
  • src/routes/chromium/tests/json.spec.ts
  • src/routes/chromium/tests/websocket.spec.ts
  • src/routes/edge/tests/page-websocket.spec.ts
  • src/routes/edge/ws/page.ts
  • src/routes/management/http/sessions.get.ts
  • src/server.ts
  • src/shared/json-list.http.ts
  • src/shared/json-new.http.ts
  • src/types.ts
  • src/utils.spec.ts
  • src/utils.ts
💤 Files with no reviewable changes (2)
  • src/routes/edge/ws/page.ts
  • src/routes/chrome/ws/page.ts

@artiom
artiom marked this pull request as draft July 22, 2026 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant