Skip to content

feat(browser): add --via-extension flag to bypass debugger detection on anti-bot sites#1769

Open
BruceLoveDecimal wants to merge 3 commits into
jackwener:mainfrom
BruceLoveDecimal:feat/no-debugger-eval
Open

feat(browser): add --via-extension flag to bypass debugger detection on anti-bot sites#1769
BruceLoveDecimal wants to merge 3 commits into
jackwener:mainfrom
BruceLoveDecimal:feat/no-debugger-eval

Conversation

@BruceLoveDecimal
Copy link
Copy Markdown
Contributor

Closes #1757

Problem

opencli browser <profile> eval <js> currently routes all JS execution through chrome.debugger.attach() (CDP). Sites like BOSS直聘 (zhipin.com) detect debugger attachment within ~100ms and immediately redirect the tab to about:blank, making eval impossible even when the user is browsing the page normally.

CDP attachment is detectable via multiple signals:

  • The "Browser Bridge started debugging…" infobar causes a visualViewport reflow
  • debugger; statements actually pause execution once a debugger is attached (timing-detectable)
  • Runtime.enable has observable side effects on console / Function.prototype / microtask timing
  • First-attach cold-start latency fingerprint

Solution

Add a --via-extension flag that routes eval through chrome.scripting.executeScript() (MAIN world) instead of CDP. This is the same mechanism used by ad-blockers and password managers — page JS cannot detect it without breaking itself for all normal extension users.

# default: CDP path — full features, detectable by anti-bot sites
opencli browser work eval "document.title"

# --via-extension: scripting API path — invisible to anti-bot, limited return types
opencli browser work eval "document.title" --via-extension

Changes

File Change
extension/manifest.json Add "scripting" permission
extension/src/protocol.ts Add noDebugger?: boolean to Command interface
extension/src/cdp.ts Add evaluateViaScripting() — uses chrome.scripting.executeScript with world: 'MAIN' and an async indirect-eval wrapper
extension/src/background.ts Branch in handleExec: noDebugger routes to evaluateViaScripting; --via-extension + --frame returns a clear error
src/browser/daemon-client.ts Add noDebugger?: boolean to DaemonCommand
src/browser/page.ts Add evaluateNoDebugger() method
src/types.ts Declare evaluateNoDebugger? on IPage
src/cli.ts Add --via-extension option to browser eval

Known Limitations (intentional for v1)

--via-extension is not a drop-in replacement for the default CDP path:

  • Return values must be structured-cloneable — no DOM nodes, functions, or circular references
  • No remote object handles — CDP returns objectId references you can re-use; scripting API returns plain values only
  • Weaker error reporting — errors come back stringified, full stack traces are lost
  • --frame is unsupported — combining --via-extension with --frame returns a clear error message; frame support can be added later via chrome.webNavigation.getAllFrames
  • No console interception — the CDP path can observe page console output; this path cannot

Execution World

The implementation uses world: 'MAIN' so that eval can access page-side JS state (Vue/React instances, window.xxx, etc.). This is required for the primary use case (reading el.__vue__.jobList on zhipin.com). world: 'ISOLATED' support can be added as a follow-up flag if needed.

Manifest Permission Note

Adding "scripting" to manifest.json will prompt users to re-approve the Browser Bridge extension on next update. Worth calling out in release notes.

E2E Test Results

Tested locally against zhipin.com:

--via-extension (4 consecutive evals — page never redirected):

eval 1: document.title  → "BOSS直聘-找工作BOSS直聘直接谈!招聘求职找工作!"  ✅
eval 2: location.href   → "https://www.zhipin.com/hangzhou/?seoRefer=index"  ✅
eval 3: location.href   → "https://www.zhipin.com/hangzhou/?seoRefer=index"  ✅  (page intact)
eval 4: DOM query       → undefined (correct — selector absent on homepage)  ✅

CDP path (reproduced the issue):

eval 1: document.title  → "BOSS直聘-..."  ✅  (before redirect)
eval 2: location.href   → "about:blank"  ❌  (redirected within ~100ms of attach)
eval 3: location.href   → "about:blank"  ❌

🤖 Generated with Claude Code

刘启灏 and others added 3 commits May 27, 2026 16:29
…on anti-bot sites

Closes jackwener#1757

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- extension/src/cdp.test.ts: 8 unit tests for evaluateViaScripting() covering
  happy path, error propagation, empty results, and verifying chrome.debugger is
  not called
- extension/src/background.test.ts: 4 integration tests for handleExec noDebugger
  path, including --frame conflict error and result forwarding
- tests/e2e/browser-eval-via-extension.test.ts: 5 e2e tests using a fake daemon
  to verify CLI sends noDebugger:true, JSON output, --frame conflict exit code
- fix(background): guard isDaemonSocketActive against undefined WebSocket (Node env)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lback on old extensions

P1: Replace noDebugger:true on 'exec' action with a dedicated 'exec-via-scripting'
action. Old extensions that don't recognise the action return 'Unknown action'
rather than silently falling back to CDP — exactly the behaviour the flag is
meant to avoid.

P2: Detect CSP-related errors in evaluateViaScripting and surface a targeted
hint explaining that --via-extension runs in the page's MAIN world and is
subject to its CSP (sites blocking unsafe-eval will fail here, while CDP
bypasses CSP by default). Update --via-extension help text to mention the
limitation upfront.

- protocol.ts: add 'exec-via-scripting' to Action union; remove noDebugger field
- background.ts: split handleExecViaScripting() out of handleExec(); expose via __test__
- daemon-client.ts: add 'exec-via-scripting' to action union; remove noDebugger field
- page.ts: send 'exec-via-scripting' action instead of exec+noDebugger
- cdp.ts: rename error prefix to --via-extension; add CSP error detection
- cli.ts: note CSP limitation in --via-extension flag description
- tests: update all assertions to match new action name and error strings

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

[Feature]: browser eval --no-debugger mode — execute JS via extension scripting API instead of chrome.debugger

1 participant