fix(desktop): keep the native preview User-Agent so Turnstile passes#7110

merged1
main
GitHub fork: fix/preview-turnstile-user-agent
openedAug 15, 2026byAakriaueno
View on GitHubTwo-way sync enabledPR last imported 20d ago

What Changed

apps/desktop/src/preview/BrowserSession.ts no longer rewrites the preview guest's User-Agent (the getUserAgent() → strip Electron/… / t3code/… → setUserAgent() block is removed). A regression test asserts the guest's effective User-Agent stays equal to Electron's native one (the mock applies setUserAgent calls, so any reintroduced rewrite fails it — verified by mutation-testing it against the old code).

I checked for other UA-touching paths — app.userAgentFallback, a useragent attribute on the <webview>, webRequest header rewriting, other session setup — there are none, and the removal leaves no dead imports.

Why

Fixes #5002. On https://dash.cloudflare.com/login the Turnstile widget fails with console error 600010 and is recreated every ~3.3s, so login can never complete.

Why the rewrite existed: it shipped with the original preview panel, and the design doc annotates it as "strip electron/t3code from UA so dev preview doesn't trip bot detection". No other motivation (e.g. a specific OAuth breakage) is recorded in the history. Against Turnstile it empirically does the opposite: the rewrite is precisely what trips the bot check.

What I measured: I isolated the trigger with a minimal reproduction (akriaueno/electron-turnstile-repro), each case in a fresh session, instrumented to dump the guest's navigator.userAgent, navigator.userAgentData, and the actually-sent request headers. Across every case userAgentData is identical and no Sec-CH-UA* headers are sent at all, so the UA string is the only variable — and it alone flips the outcome. Turnstile is closed, so I don't claim the exact discriminator; the reproducible observation is that the untouched native UA passes and every rewritten variant fails.

Measured matrix and everything else that was ruled out

Electron 41.5.0 / Chromium 146, Ubuntu 24.04, fresh --user-data-dir per case. The User-Agent header and navigator.userAgent always agree; in all four cases navigator.userAgentData.brands is Not-A.Brand 24, Chromium 146 (no Google Chrome, no Electron entry) and no Sec-CH-UA* headers are sent.

UA string presented to the page/siteTurnstile
native: … <app>/0.0.0 Chrome/146.0.7680.216 Electron/41.5.0 Safari/537.36passes
setUserAgent() with the unchanged native stringpasses
app token stripped, Electron/… keptfails (600010 loop)
Electron/… stripped (what this app shipped)fails (600010 loop)

The no-op re-set passing rules out the setUserAgent() call itself; the app-token-stripped case failing shows no single token is the trigger.

Also ruled out as causes during the investigation: pre-granted permission handlers (the repro grants them like this app does — still passes), CDP debugger attachment (real Chrome passes with DevTools open; a diagnostic build that never attaches still looped), the preview preload / contextIsolation (a build without them still looped), WebGL/GPU state (real Chrome passes on the same machine with WebGL blocklisted), and BrowserWindow vs <webview>.

Trade-off: sites now see the stock Electron UA (Electron and app tokens included) instead of a Chrome-looking one — exactly what a default Electron <webview> sends, and the identity Turnstile accepts. The flip side is that services which block embedded browsers by UA sniffing (notably Google OAuth's disallowed_useragent policy) can now recognize the preview as Electron. If that ever needs solving, the honest route is overriding userAgentMetadata together with the UA via CDP (Network.setUserAgentOverride) so every layer stays consistent — a much larger, fingerprint-chasing change I deliberately left out.

Verified on Linux (Ubuntu 24.04): the login challenge completes and sign-in proceeds. vp test run apps/desktop/src/preview/BrowserSession.test.ts passes (7 tests); tsgo --noEmit in apps/desktop reports no new diagnostics.

Screencast

https://github.com/user-attachments/assets/044f1a87-817d-4109-a84e-19b4df4360ce

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes — N/A, no UI changes
  • I included a video for animation/interaction changes — screencast of the Turnstile behavior above

Note

Medium Risk Preview identity visible to sites changes (full Electron UA vs Chrome-like), which can affect bot/OAuth UA policies, though scope is limited to preview partition sessions.

Overview Stops rewriting the desktop preview guest session User-Agent in BrowserSession.getSession — the previous getUserAgent() → strip Electron/… and t3code/… → setUserAgent() path is removed so the webview keeps Electron’s native string. That fixes Cloudflare Turnstile error 600010 / endless challenge loops on sites like the Cloudflare login (#5002).

Adds a regression test that models a session whose setUserAgent updates the effective UA and asserts it still matches the native value after getSession, so any future rewrite fails CI.

Reviewed by Cursor Bugbot for commit 1043f766bcc4bcc5cc8c06b6586da93cd77a549e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Keep native Electron User-Agent in desktop preview session so Cloudflare Turnstile passes

Removes the UA rewriting logic in BrowserSession.getSession that stripped Electron and t3code tokens from the session's User-Agent. Cloudflare Turnstile fails when the UA is modified, so the guest session now retains Electron's native UA unchanged.

Macroscope summarized 1043f76.

Summary by CodeRabbit

  • Bug Fixes

    • Preserved Electron’s native browser User-Agent for desktop sessions.
    • Fixed login failures with Cloudflare Turnstile caused by User-Agent rewriting.
  • Tests

    • Added coverage confirming the User-Agent remains unchanged when a browser session is created.
Synced from GitHub

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: e878f1b5-68ed-47c9-b432-43ba5721f34e

📥 Commits

Reviewing files that changed from the base of the PR and between a43f9b45ae85caf37e0be8270ad3d27365ece2bd and 353a5ee634107b307edfd319a70531ba756396b7.

📒 Files selected for processing (2)
  • apps/desktop/src/preview/BrowserSession.test.ts
  • apps/desktop/src/preview/BrowserSession.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The preview browser no longer rewrites Electron’s native User-Agent. A regression test verifies that session creation preserves the native value.

Changes

Native User-Agent handling

Layer / File(s)Summary
Preserve native User-Agent
apps/desktop/src/preview/BrowserSession.ts, apps/desktop/src/preview/BrowserSession.test.ts
getSession no longer strips Electron and t3code tokens from the User-Agent. The mock type is more precise, and a test verifies that the native User-Agent remains unchanged.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to fc47a

Preview sessions preserve their native User-Agent, and the regression test guards against reintroducing a rewrite. No actionable merge risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly and concisely describes the primary change: preserving the native preview User-Agent so Cloudflare Turnstile passes.
Description check✅ PassedThe description includes What Changed, Why, UI impact, checklist status, verification results, reproduction details, and trade-offs. It is complete and directly related to the pull request.
Linked Issues check✅ PassedIssue #5002 requires a stable Cloudflare login and Turnstile flow. BrowserSession.getSession no longer rewrites the session User-Agent, so the guest keeps Electron's native value. The new regression…
Out of Scope Changes check✅ PassedThe changes are limited to preview session User-Agent handling and its regression test. The permission handlers remain unchanged. The changes directly support issue #5002 and do not demonstrate unrela…
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Synced from GitHub

Approvability

Verdict: Approved 1043f76

Straightforward bug fix that removes User-Agent rewriting code which was breaking Cloudflare Turnstile login flows. The change is limited to removing problematic behavior and includes a regression test to prevent reintroduction.

You can customize Macroscope's approvability policy. Learn more.

Note: GPT-6 on behalf of shivam (@shivamhwp).

Please rebase this against current main and repeat the native Turnstile check on the current Electron 44.1.0 runtime. The PR's measured matrix used Electron 41.5.0; retaining the native User-Agent still passes the session regression, but that regression cannot establish current challenge behavior. Keep the existing permission handlers when resolving the session changes.

Added 1 commit

  • fix(desktop): keep the native preview User-Agent so Turnstile passesfc47acb
Synced from GitHub

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.