Skip to content

fix: Cloudflare/CAPTCHA verification failures in browser panel - #1877

Merged
lawrencecchen merged 1 commit into
manaflow-ai:mainfrom
Jesssullivan:sid/fix-captcha-upstream
Mar 21, 2026
Merged

lawrencecchen merged 1 commit into
manaflow-ai:mainfrom
Jesssullivan:sid/fix-captcha-upstream

Conversation

@Jesssullivan

@Jesssullivan Jesssullivan commented Mar 20, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1429

telemetryHookBootstrapScriptSource and addressBarFocusTrackingBootstrapScript are injected with forMainFrameOnly: false, so they run inside cross-origin CAPTCHA iframes (challenges.cloudflare.com, google.com/recaptcha, hcaptcha.com).

CAPTCHA providers fingerprint the JS environment inside their iframe and detect:

  • Overridden console.log/warn/error/info/debug (the telemetry hook replaces all five)
  • Non-standard window.__cmux* globals (__cmuxHooksInstalled, __cmuxConsoleLog, __cmuxErrorLog, __cmuxAddressBarFocusState, etc.)

This causes Cloudflare Turnstile, reCAPTCHA, and hCaptcha to fail or score the session as a bot — which is the behavior described in #1429 (Cloudflare verification stuck on claude.ai and other protected sites).

Fix: forMainFrameOnly: false → forMainFrameOnly: true. Both scripts only need to run in the top-level page context — sub-frame telemetry isn't needed, and address bar focus tracking only applies to the main document.

-Jess


Summary by cubic

Fixes CAPTCHA verification failures in the browser panel by scoping injected scripts to the main frame only. Prevents console overrides and __cmux* globals from running inside cross-origin CAPTCHA iframes.

  • Bug Fixes
    • Set forMainFrameOnly: true for telemetryHookBootstrapScriptSource and addressBarFocusTrackingBootstrapScript to avoid running in CAPTCHA iframes (reCAPTCHA, hCaptcha, Cloudflare Turnstile).
    • Telemetry and focus tracking continue to run in the top-level page where they’re needed.

Written for commit 9394774. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Restricted telemetry and address bar tracking to the main frame, preventing unnecessary execution in cross-origin iframes.

CAPTCHA providers (reCAPTCHA, hCaptcha, Cloudflare Turnstile) detect
environment tampering in their cross-origin iframes. With
forMainFrameOnly: false, the telemetry hooks (overridden console.*)
and address bar focus tracker (__cmux* globals) run inside CAPTCHA
iframes, causing challenges to fail or score the session as a bot.

Change forMainFrameOnly from false to true on:
- telemetryHookBootstrapScriptSource
- addressBarFocusTrackingBootstrapScript

Both only need to run in the top-level page context.

Fixes manaflow-ai#1429
@vercel

vercel Bot commented Mar 20, 2026

Copy link
Copy Markdown

@Jesssullivan is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Mar 20, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Modified two WKUserScript injections in BrowserPanel to restrict execution to main frames only by changing forMainFrameOnly from false to true for telemetry hook bootstrap and address bar focus tracking scripts, preventing them from running in cross-origin iframes.

Changes

Cohort / File(s) Summary
Script Injection Configuration
Sources/Panels/BrowserPanel.swift
Changed forMainFrameOnly parameter from false to true for telemetryHookBootstrapScriptSource and addressBarFocusTrackingBootstrapScript instances, restricting these injected scripts to execute only in the main frame and not in cross-origin iframes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 Whiskers twitch with glee,
Scripts bound to frames set free,
Cloudflare's walls now bend—
The browser's dance can mend!
Cross-origin chains released,
Access flows—the quest increased! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing CAPTCHA verification failures by scoping injected scripts to the main frame only.
Description check ✅ Passed The description comprehensively explains the problem, root cause, and the fix, exceeding template requirements with detailed technical context.
Linked Issues check ✅ Passed The PR directly addresses issue #1429 by preventing console overrides and __cmux* globals from running in CAPTCHA iframes, allowing verification flows to complete.
Out of Scope Changes check ✅ Passed All changes are strictly scoped to the fix: only the forMainFrameOnly parameter is modified for two bootstrap scripts in BrowserPanel.swift.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

You can enable review details to help with troubleshooting, context usage and more.

Enable the reviews.review_details setting to include review details such as the model used, the time taken for each step and more in the review comments.

@Jesssullivan Jesssullivan changed the title Fix Cloudflare/CAPTCHA verification failures in browser panel fix: Cloudflare/CAPTCHA verification failures in browser panel Mar 20, 2026
@Jesssullivan
Jesssullivan marked this pull request as ready for review March 20, 2026 19:29
@greptile-apps

greptile-apps Bot commented Mar 20, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes CAPTCHA verification failures (Cloudflare Turnstile, reCAPTCHA, hCaptcha) on the browser panel by changing forMainFrameOnly: false to forMainFrameOnly: true for two injected WKUserScripts — telemetryHookBootstrapScriptSource and addressBarFocusTrackingBootstrapScript. The root cause was that both scripts ran inside cross-origin CAPTCHA iframes, where they installed __cmux* globals and overrode all five console.* methods — telltale signs of environment tampering that CAPTCHA providers fingerprint and penalise.

  • The fix is correctly targeted: both scripts only need the main-frame context (telemetry is per-page, address-bar focus tracking is a top-level-document concern).
  • Behavior change to note: Same-origin subframes embedded in the page will no longer have focus tracking installed. Any editable input inside a same-origin <iframe> will no longer participate in the address-bar focus-restore mechanism. The author considers this acceptable.
  • Pre-existing dead-code concern: The postMessage bridge listener inside addressBarFocusTrackingBootstrapScript (which was designed to bubble focus state from subframes to the main frame) is now permanently unreachable. Since the bootstrap script no longer runs in iframes, no cmuxAddressBarFocusState postMessage will ever arrive at the listener. The bridge should be removed or annotated to avoid confusing future developers.
  • Separately, dialogTelemetryHookBootstrapScriptSource is defined as a static let but is never passed to addUserScript — this is a pre-existing dead-code item unrelated to this PR.

Confidence Score: 4/5

  • Safe to merge — the fix is correctly scoped and directly addresses the root cause with no risk of regressions beyond the intentional loss of same-origin iframe focus tracking.
  • The change is a minimal two-line diff with a clear, well-evidenced rationale. The only remaining concern is dead code inside the focus-tracking bootstrap script (the cross-frame postMessage bridge), which is harmless but could mislead future readers. No logic errors or new security issues introduced.
  • No files require special attention beyond the dead-code bridge in addressBarFocusTrackingBootstrapScript.

Important Files Changed

Filename Overview
Sources/Panels/BrowserPanel.swift Changes forMainFrameOnly: false → true for both injected user scripts; fix is correct and well-motivated, but the cross-frame postMessage bridge inside addressBarFocusTrackingBootstrapScript is now permanently dead code.

Sequence Diagram

sequenceDiagram
    participant WK as WKWebView
    participant Main as Main Frame (claude.ai)
    participant CF as Cloudflare CAPTCHA iframe

    Note over WK,CF: BEFORE (forMainFrameOnly: false)
    WK->>Main: inject telemetryHookBootstrap + addressBarFocusTracking
    WK->>CF: inject telemetryHookBootstrap + addressBarFocusTracking
    CF-->>CF: __cmux* globals & console.* overrides detected
    CF-->>Main: ❌ CAPTCHA fails (bot fingerprint detected)

    Note over WK,CF: AFTER (forMainFrameOnly: true)
    WK->>Main: inject telemetryHookBootstrap + addressBarFocusTracking
    WK--xCF: scripts NOT injected into cross-origin iframe
    CF-->>CF: clean JS environment, no __cmux* pollution
    CF-->>Main: ✅ CAPTCHA passes
Loading

Comments Outside Diff (1)

  1. Sources/Panels/BrowserPanel.swift, line 1952-1961 (link)

    P2 Dead code: cross-frame postMessage bridge is now unreachable

    With addressBarFocusTrackingBootstrapScript now scoped to forMainFrameOnly: true, the postMessage bridge listener installed on the main frame (which listened for focus-state updates bubbled up by the same script running inside same-origin iframes) will never fire. Since iframes no longer receive the bootstrap script, no postMessage({ cmuxAddressBarFocusState: ... }) will ever be sent, making the "message" event handler installed here permanently dead code.

    Similarly, the syncState → postMessage branch at line 1944–1946 (inside the bootstrap script itself) is also unreachable: the bootstrap now always runs in the main frame where window.top === window, so the window.top !== window guard is never satisfied.

    Consider removing or commenting out the iframe bridge logic, both in syncState and the listener, since it can no longer trigger:

    // If this is ever re-enabled for same-origin subframes, restore the
    // postMessage bridge below. Currently unreachable because forMainFrameOnly: true.

    This avoids confusing future readers into thinking iframes still propagate focus state to the main frame.

Last reviewed commit: "Fix CAPTCHA failures..."

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file


Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/Panels/BrowserPanel.swift`:
- Around line 2497-2502: The bootstrap script was added with forMainFrameOnly
true which prevents same-origin iframes from tagging focused controls; instead,
add the user script to all frames (remove/false the forMainFrameOnly flag on the
addUserScript call) and change Self.addressBarFocusTrackingBootstrapScript to
gate itself: run normally only when the frame is same-origin with the top
(detect with a try/catch that accesses a top-level property like
window.top.document or window.top.location to see if it throws and return early
on cross-origin), otherwise continue to install the iframe focus-relay logic so
addressBarFocusCaptureScript can see and restore focus for same-origin embedded
editors/forms.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e81236ec-7798-4f67-836b-02d73c81e756

📥 Commits

Reviewing files that changed from the base of the PR and between cc0fc55 and 9394774.

📒 Files selected for processing (1)
  • Sources/Panels/BrowserPanel.swift

Comment on lines +2497 to +2502
// Main frame only — same CAPTCHA interference concern as telemetry hooks.
configuration.userContentController.addUserScript(
WKUserScript(
source: Self.addressBarFocusTrackingBootstrapScript,
injectionTime: .atDocumentStart,
forMainFrameOnly: false
forMainFrameOnly: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

This drops same-origin iframe focus restore.

addressBarFocusCaptureScript only sees the top document’s activeElement. The child-frame bootstrap is what tags focused controls inside iframes and relays that state upward, so making it main-frame-only means embedded same-origin editors/forms will no longer regain focus after the user leaves and re-enters the omnibar. If the CAPTCHA issue is limited to cross-origin frames, gate the bootstrap inside the script instead of disabling all subframes.

♻️ Possible fix
         configuration.userContentController.addUserScript(
             WKUserScript(
                 source: Self.addressBarFocusTrackingBootstrapScript,
                 injectionTime: .atDocumentStart,
-                forMainFrameOnly: true
+                forMainFrameOnly: false
             )
         )
     (() => {
       try {
+        if (window.top !== window) {
+          try {
+            if (window.top.location.origin !== window.location.origin) return true;
+          } catch (_) {
+            return true;
+          }
+        }
         if (window.__cmuxAddressBarFocusTrackerInstalled) return true;
         window.__cmuxAddressBarFocusTrackerInstalled = true;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Panels/BrowserPanel.swift` around lines 2497 - 2502, The bootstrap
script was added with forMainFrameOnly true which prevents same-origin iframes
from tagging focused controls; instead, add the user script to all frames
(remove/false the forMainFrameOnly flag on the addUserScript call) and change
Self.addressBarFocusTrackingBootstrapScript to gate itself: run normally only
when the frame is same-origin with the top (detect with a try/catch that
accesses a top-level property like window.top.document or window.top.location to
see if it throws and return early on cross-origin), otherwise continue to
install the iframe focus-relay logic so addressBarFocusCaptureScript can see and
restore focus for same-origin embedded editors/forms.

@Jesssullivan

Copy link
Copy Markdown
Contributor Author

I've tested this against glab, gh; so far so good. 👀

Testing against both #1876 and an alternative JS bridge based implementation for less prescriptive webauthn context management.

@lawrencecchen
lawrencecchen merged commit ae5b81c into manaflow-ai:main Mar 21, 2026
14 of 15 checks passed
@lawrencecchen

Copy link
Copy Markdown
Contributor

Thank you for the contribution!

@michaelangeloio

Copy link
Copy Markdown

is this released yet?

@michaelangeloio

Copy link
Copy Markdown

tried on nightly and got no luck with gitlab

@Jesssullivan

Jesssullivan commented Mar 22, 2026 •

Copy link
Copy Markdown
Contributor Author

tried on nightly and got no luck with gitlab

@michaelangeloio I think nightly does not have this yet, at least as of 13 hours ago- some other issues with nightly parity as well re. attestation 👀

Jesssullivan added a commit to Jesssullivan/cmux that referenced this pull request Mar 26, 2026
Ingests all upstream fixes since 2026-03-22 including:
- Fix Cmd+N crash: retain snapshot workspaces (manaflow-ai#2183, manaflow-ai#2181, manaflow-ai#2178, manaflow-ai#2173)
- Fix browser pane restore after reopen (manaflow-ai#2141)
- Fix Ghostty resize_split keybind (manaflow-ai#1899)
- Reduce shell integration prompt latency (manaflow-ai#2109)
- Fix command palette focus after terminal find (manaflow-ai#2089)
- Add Codex CLI hooks (manaflow-ai#2103)
- Add cmux.json custom commands (manaflow-ai#2011)
- Fix window position restore on relaunch (manaflow-ai#2129)

Conflict resolution:
- BrowserPanel.swift: accepted upstream configureWebViewConfiguration()
  refactor (already includes our forMainFrameOnly:true CAPTCHA fix from PR manaflow-ai#1877)

Fork-specific files preserved:
- Sources/Panels/WebAuthn{Coordinator,BridgeJavaScript}.swift
- Sources/FIDO2/module.modulemap
- vendor/ctap2 submodule
- cmux.entitlements (with camera/audio-input removed)
- cmux.embedded.entitlements
- .github/workflows/fork-{ci,release}.yml
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
…-upstream

fix: Cloudflare/CAPTCHA verification failures in browser panel
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.

Cloudflare security verification cannot complete in embedded browser

3 participants