Skip to content

fix browser click timeouts for existing-session routes#63524

Merged
steipete merged 3 commits into
openclaw:mainfrom
dongseok0:fix/browser-click-timeout-recovery
Apr 22, 2026
Merged

fix browser click timeouts for existing-session routes#63524
steipete merged 3 commits into
openclaw:mainfrom
dongseok0:fix/browser-click-timeout-recovery

Conversation

@dongseok0

@dongseok0 dongseok0 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add Chrome MCP click timeout handling so stuck existing-session clicks fail fast and reconnect cleanly on the next request
  • propagate browser act click timeout and abort signals through the route and Playwright interaction path while preserving the Playwright SSRF navigation guard from main
  • cover the regression with browser route and Chrome MCP tests, including a pre-aborted signal case, and verify the fix with a real OpenClaw browser flow

Fixes #57158

Test Plan

  • pnpm test extensions/browser/src/browser/chrome-mcp.test.ts extensions/browser/src/browser/routes/agent.existing-session.test.ts extensions/browser/src/browser/client-fetch.loopback-auth.test.ts extensions/browser/src/browser/pw-tools-core.interactions.navigation-guard.test.ts extensions/browser/src/browser/pw-tools-core.interactions.evaluate.abort.test.ts
  • pnpm build
  • ./scripts/restart-mac.sh --no-sign --no-attach-only
  • openclaw browser open https://example.com
  • openclaw browser snapshot
  • openclaw browser click e2

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f63e14870

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +343 to +346
const callPromise = session.client.callTool({
name,
arguments: args,
}) as Promise<ChromeMcpToolResult>;

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.

P1 Badge Skip MCP click call when request signal is already aborted

This path still invokes session.client.callTool(...) even when opts.signal.aborted is already true, because the abort branch only rejects abortPromise and does not return before creating callPromise. For side-effecting tools like click, a canceled request can still execute the browser action and mutate page state after the caller has timed out/canceled. This is reachable with pre-aborted dispatch signals (for example, an upstream abort propagated into route dispatch), so cancellation is not reliably honored.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 33864003ae4cf20c4a52e17258c4b35afa84aaf5. chrome-mcp.ts now short-circuits before creating session.client.callTool(...) when the signal is already aborted, and it re-checks after listener registration so pre-aborted requests cannot execute a side-effecting MCP click.

@greptile-apps

greptile-apps Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds click timeout and abort-signal propagation for the Chrome MCP existing-session path: callTool races the MCP client call against a timeout/abort promise and tears down the session on failure so the next request reconnects cleanly. The Chrome MCP changes and the new tests are correct.

However, the PR also removes assertInteractionNavigationCompletedSafely, scheduleDelayedInteractionNavigationGuard, and the ssrfPolicy parameter from clickViaPlaywright in pw-tools-core.interactions.ts, and drops the corresponding ssrfPolicy pass-through in agent.act.ts. These were the SSRF post-click navigation guards for the managed-browser (Playwright) path; their removal allows a click to navigate to a private-network URL without being caught by the configured SSRF policy.

Confidence Score: 4/5

Not safe to merge as-is: the SSRF post-click navigation guard for the Playwright browser path was inadvertently removed.

The existing-session click timeout fix is correct and well-tested. However, the large deletion in pw-tools-core.interactions.ts removes assertInteractionNavigationCompletedSafely and the ssrfPolicy parameter from clickViaPlaywright, which was the SSRF guard for managed-browser click-triggered navigations. The base branch passed ssrfPolicy: ctx.state().resolved.ssrfPolicy to the click request; the new code omits it entirely. This is a current security-boundary regression that needs to be restored before landing.

extensions/browser/src/browser/pw-tools-core.interactions.ts and extensions/browser/src/browser/routes/agent.act.ts — the SSRF navigation guard and ssrfPolicy threading must be restored for the Playwright click path.

Vulnerabilities

  • SSRF bypass on Playwright click path (pw-tools-core.interactions.ts): assertInteractionNavigationCompletedSafely and the ssrfPolicy parameter were removed from clickViaPlaywright. Previously, any navigation triggered by a Playwright-driven click was inspected against the configured SSRF policy; that guard is now gone. A page with a link to a private-network URL (e.g. http://192.168.1.1/admin) can now be navigated via a click action without triggering the SSRF block, in deployments where dangerouslyAllowPrivateNetwork is not set.

Comments Outside Diff (1)

  1. extensions/browser/src/browser/pw-tools-core.interactions.ts, line 80-161 (link)

    P1 security SSRF post-click navigation guard removed from Playwright path

    clickViaPlaywright previously accepted ssrfPolicy and wrapped the locator click inside assertInteractionNavigationCompletedSafely, which detected any navigation triggered by the click and enforced the SSRF policy against it. Both the ssrfPolicy parameter and the navigation guard wrapper have been removed in this PR, and the route handler (agent.act.ts) no longer passes ssrfPolicy to click requests.

    Concretely: if a managed-browser page has a link or button that navigates to a private network URL (e.g. http://192.168.1.1/admin), clicking it via the Playwright path now bypasses the SSRF check that previously blocked such navigations when dangerouslyAllowPrivateNetwork is not set. The base branch passed ssrfPolicy: ctx.state().resolved.ssrfPolicy to clickViaPlaywright (old agent.act.ts line 542); this PR removes that field entirely.

    The fix for click timeouts in the existing-session path is unrelated to this guard. assertInteractionNavigationCompletedSafely, scheduleDelayedInteractionNavigationGuard, and the ssrfPolicy parameter should be restored to clickViaPlaywright (and threaded back through from the route handler) before merging.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/browser/src/browser/pw-tools-core.interactions.ts
    Line: 80-161
    
    Comment:
    **SSRF post-click navigation guard removed from Playwright path**
    
    `clickViaPlaywright` previously accepted `ssrfPolicy` and wrapped the locator click inside `assertInteractionNavigationCompletedSafely`, which detected any navigation triggered by the click and enforced the SSRF policy against it. Both the `ssrfPolicy` parameter and the navigation guard wrapper have been removed in this PR, and the route handler (`agent.act.ts`) no longer passes `ssrfPolicy` to click requests.
    
    Concretely: if a managed-browser page has a link or button that navigates to a private network URL (e.g. `http://192.168.1.1/admin`), clicking it via the Playwright path now bypasses the SSRF check that previously blocked such navigations when `dangerouslyAllowPrivateNetwork` is not set. The base branch passed `ssrfPolicy: ctx.state().resolved.ssrfPolicy` to `clickViaPlaywright` (old `agent.act.ts` line 542); this PR removes that field entirely.
    
    The fix for click timeouts in the existing-session path is unrelated to this guard. `assertInteractionNavigationCompletedSafely`, `scheduleDelayedInteractionNavigationGuard`, and the `ssrfPolicy` parameter should be restored to `clickViaPlaywright` (and threaded back through from the route handler) before merging.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/browser/src/browser/pw-tools-core.interactions.ts
Line: 80-161

Comment:
**SSRF post-click navigation guard removed from Playwright path**

`clickViaPlaywright` previously accepted `ssrfPolicy` and wrapped the locator click inside `assertInteractionNavigationCompletedSafely`, which detected any navigation triggered by the click and enforced the SSRF policy against it. Both the `ssrfPolicy` parameter and the navigation guard wrapper have been removed in this PR, and the route handler (`agent.act.ts`) no longer passes `ssrfPolicy` to click requests.

Concretely: if a managed-browser page has a link or button that navigates to a private network URL (e.g. `http://192.168.1.1/admin`), clicking it via the Playwright path now bypasses the SSRF check that previously blocked such navigations when `dangerouslyAllowPrivateNetwork` is not set. The base branch passed `ssrfPolicy: ctx.state().resolved.ssrfPolicy` to `clickViaPlaywright` (old `agent.act.ts` line 542); this PR removes that field entirely.

The fix for click timeouts in the existing-session path is unrelated to this guard. `assertInteractionNavigationCompletedSafely`, `scheduleDelayedInteractionNavigationGuard`, and the `ssrfPolicy` parameter should be restored to `clickViaPlaywright` (and threaded back through from the route handler) before merging.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(browser): propagate click aborts thr..." | Re-trigger Greptile

@dongseok0
dongseok0 force-pushed the fix/browser-click-timeout-recovery branch from 2f63e14 to 3386400 Compare April 9, 2026 03:59
@dongseok0

Copy link
Copy Markdown
Contributor Author

Addressed the review follow-ups in 33864003ae4cf20c4a52e17258c4b35afa84aaf5. The rebase onto current main preserved the Playwright SSRF post-click navigation guard and ssrfPolicy threading, while the Chrome MCP path now skips side-effecting click dispatch when the request signal is already aborted. I also updated the PR body to tag #57158 and reran the targeted browser tests plus pnpm build.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33864003ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 440 to 442
await awaitEvalWithAbort(
locator.click({
timeout,

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.

P1 Badge Prevent click dispatch after abort during delayed clicks

If delayMs is non-zero and the request aborts during the setTimeout delay, abortPromise is already rejected but this code still evaluates locator.click(...) (and similarly locator.dblclick(...) above) before awaitEvalWithAbort runs the race. Because function arguments are evaluated eagerly, the click command can still be sent to Playwright after cancellation, so a timed-out/canceled request may still mutate page state. Race the delay itself against the abort signal (or re-check abort) before constructing the click promise.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the fix/browser-click-timeout-recovery branch from 3386400 to ff0ad18 Compare April 22, 2026 02:06
@steipete
steipete force-pushed the fix/browser-click-timeout-recovery branch from ff0ad18 to aadd692 Compare April 22, 2026 02:08
@steipete
steipete merged commit e92079b into openclaw:main Apr 22, 2026
3 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed via rebase onto latest main.\n\nGate before merge:\n- pnpm test extensions/browser/src/browser/chrome-mcp.test.ts extensions/browser/src/browser/routes/agent.existing-session.test.ts extensions/browser/src/browser/pw-tools-core.interactions.evaluate.abort.test.ts: 25 passed\n- pnpm check:changed: 80 files / 717 tests passed\n- note: one prior changed-gate run hit a transient chrome.test.ts diagnostic race; rerun of extensions/browser/src/browser/chrome.test.ts passed 27/27, then final pnpm check:changed passed\n\nLand commit: aadd692\nMerge commit: e92079b\n\nThanks @dongseok0!

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aadd69245f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +346 to +350
if (signal) {
racers.push(
new Promise<never>((_, reject) => {
abortListener = () => reject(signal.reason ?? new Error("aborted"));
signal.addEventListener("abort", abortListener, { once: true });

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.

P1 Badge Re-check abort after wiring Chrome MCP abort listener

After the initial signal.aborted guard, rawCall is started and the abort listener is attached, but there is no second aborted check after addEventListener. If the signal flips to aborted in that small window, the abort event can be missed and Promise.race will wait on rawCall/timeout instead of canceling, so a canceled click may still execute and mutate page state. This is the same race pattern already handled in clickViaPlaywright (with a post-registration check) and should be mirrored here.

Useful? React with 👍 / 👎.

medikoo pushed a commit to medikoo/openclaw that referenced this pull request Apr 24, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request May 7, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Browser automation act/click times out even though open and snapshot work

2 participants