Skip to content

fix(browser): stop false-flagging normal ChatGPT pages (incl. GPT-5.6 "Work" UI) as Cloudflare challenges#308

Open
StartupBros wants to merge 2 commits into
steipete:mainfrom
StartupBros:fix/cloudflare-false-positive-upstream
Open

fix(browser): stop false-flagging normal ChatGPT pages (incl. GPT-5.6 "Work" UI) as Cloudflare challenges#308
StartupBros wants to merge 2 commits into
steipete:mainfrom
StartupBros:fix/cloudflare-false-positive-upstream

Conversation

@StartupBros

@StartupBros StartupBros commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Problem

isCloudflareChallenge treated any script[src*="/challenge-platform/"] as proof of a Cloudflare interstitial. Cloudflare bot-management injects that script on perfectly normal pages, and ChatGPT's GPT-5.6 "Work" UI does so consistently: oracle then aborted healthy, signed-in sessions with stage=cloudflare-challenge before ever submitting the prompt. Under an automation wrapper this is costly twice over: the run dies, and a wrapper that retries "into" the phantom challenge can trip real anti-bot defenses.

Fix

Positive-evidence classification instead of script-presence inference:

  • If the ChatGPT app shell rendered, it is never a challenge, regardless of injected scripts.
  • Otherwise require actual challenge UI (title "Attention Required!/Just a moment", #challenge-form / #cf-challenge-running / turnstile iframe, or challenge body text) on a short, shell-less page.

Validation

  • pnpm run typecheck, oxlint, oxfmt --check, full browser suite (627 passed) on this branch (cherry-picked clean onto current main, no dependency on fix(browser): finalize assistant turns on positive completion proof (stop preamble/mid-stream capture) #301).
  • Production evidence from our fork running this fix since 2026-07-09: the previously reproducible cloudflare-challenge aborts on GPT-5.6 Work-UI pages stopped entirely across dozens of long browser reviews (run ledger available on request), while genuine challenge detection still triggers on shell-less challenge pages (unit-tested for both directions).

Independent of #301 (different file/mechanism); both apply cleanly together, which is how our fork runs them.

Real-behavior proof (redacted)

Healthy GPT-5.6 "Work" UI page, live CDP capture during an active production review (2026-07-10 14:5x EDT), read straight off the conversation tab:

{"generating":true,"testidStop":1,"oldSelectorMatches":1,"oldSelectorLabels":["Stop answering"],"newSelectorMatches":1,"newSelectorLabels":["Stop answering"],"pageWideStopLabels":["Stop answering"],"cf":{"hasAppShell":true,"hasChallengeScript":true,"bodyLen":59167,"titleIsChallenge":false},"visibleProgressBars":0}

hasChallengeScript: true on a page with hasAppShell: true, a 59 KB body, and a non-challenge title: this is exactly the false-positive input (the bot-management script on a healthy page). The verdict classifier clears it via the shell signal with zero added latency; the 12s grace never engages on this page.

Production ledger (fork build with this change), overnight drain 2026-07-10 04:20-14:14 EDT: 20 long browser reviews, 18 clean and 2 unrelated capture failures, ZERO cloudflare-challenge aborts. On 2026-07-09, before this fix, stock 0.15.2 aborted healthy Work-UI runs with Cloudflare anti-bot page detected on this same account (that incident motivated the patch).

Genuine-challenge path: strong evidence (challenge title, widget, verification copy) classifies immediately, with latency unchanged from current main; that path is untouched by the grace window and pinned by the fixture tests. On the compounding concern: the grace runs at most once per ensureNotBlocked call (one navigation checkpoint), not per poll cycle, and only when the page has no app shell, no strong evidence, AND carries the script on a short body, a state that healthy pages exit as soon as hydration completes.

…UI) as Cloudflare

isCloudflareInterstitial returned true whenever the '/challenge-platform/' script was present,
but Cloudflare bot-management injects that script on NORMAL ChatGPT pages too (including the new
GPT-5.6 "Work" UI). So healthy pages were detected as challenges and the run was aborted with
stage=cloudflare-challenge (which downstream tools then treated as a hard block / backed off on).

Tighten detection to a real interstitial, in one injected predicate:
- "Just a moment" / "Attention Required ... Cloudflare" title -> challenge (unchanged strong signal);
- if the ChatGPT APP SHELL rendered (composer / conversation turns / profile / nav), it is never a
  challenge -> return false (this alone kills the false positive);
- otherwise require a genuine marker: a Cloudflare challenge widget, verification copy, or the
  script on a SHORT interstitial-sized page (content-rich app pages never qualify).

Extracted as buildCloudflareInterstitialExpression (exported for tests). Updated the ensureNotBlocked
mocks (single boolean evaluate now) and added DOM-logic tests, including the regression: app shell +
challenge script must NOT be flagged. Full browser suite green (646).
… window

Review feedback on the fork run of this change: ensureNotBlocked executes right
after navigation, which only waits for document.readyState, so a healthy SPA
load can transiently look exactly like the weak-evidence case (bot-management
script present, React app shell not yet rendered, short body) and still abort
as cloudflare-challenge.

Split the injected predicate into a verdict (strong / shell / weak). Strong
evidence (challenge title, widget, verification copy) classifies immediately;
the app shell clears immediately; weak script-only evidence must now persist
through a 12s grace window in which the shell never appears. A real
interstitial never grows an app shell, so the wait converts the race into a
correct answer and only costs seconds on genuinely ambiguous pages.

Regression tests: weak-then-shell resolves false, persistent weak resolves
true, strong is immediate, no-evidence is immediate.
@StartupBros

Copy link
Copy Markdown
Contributor Author

Pushed 10fc2de addressing review feedback from our fork run of this change: weak (script-only, shell-less, short-page) evidence must now persist through a 12s hydration grace window before classifying, closing the post-navigation race where a healthy SPA load transiently matches the weak case before React renders the app shell. Strong evidence (challenge title/widget/verification copy) still classifies immediately, and the rendered app shell still clears immediately. Full browser suite: 631 passing.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 Urgent regression or broken agent/channel workflow affecting real users now. merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 10, 2026
@clawsweeper

clawsweeper Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 10, 2026, 3:14 PM ET / 19:14 UTC.

Summary
The PR replaces script-presence Cloudflare detection with strong DOM evidence, app-shell exclusion, and a 12-second persistence check for weak evidence, plus browser regression tests.

Reproducibility: yes. Current-main source plus the submitted live CDP output establish the original script-only false positive, and the proposed verdict expression directly reproduces the new content-rich generic-body false positive without requiring a live account.

Review metrics: 3 noteworthy metrics.

  • Runtime proof: 20 long browser reviews, 0 reported Cloudflare aborts. The submitted fork ledger supports the intended healthy Work UI path but does not exercise content-rich shell-less pages containing generic verification wording.
  • Automated checks: 4 checks passed. Security and three platform builds pass, while the newly identified DOM false positive is outside their coverage.
  • Patch scope: 2 files; 187 additions, 23 deletions. The blocking defect is localized to the classifier and can be repaired with focused regression coverage.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🐚 platinum hermit
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Apply the short-page requirement to generic body-copy challenge evidence and add a regression fixture for a normal content-rich shell-less page containing “just a moment.”.

Risk before merge

  • [P1] A normal content-rich page can be aborted immediately if its recognized app-shell selectors are absent and its body contains generic text such as “just a moment” or “checking your browser.”.
  • [P1] The intentional 12-second persistence window remains an availability-sensitive tradeoff on ambiguous script-only, shell-less pages, although it is bounded and not itself a confirmed defect.

Maintainer options:

  1. Constrain generic body-copy evidence (recommended)
    Require the existing short-page condition for generic verification phrases, then add a focused content-rich false-positive regression test before merge.
  2. Accept broader phrase matching
    Merge while accepting that temporary shell absence or selector drift can convert ordinary page wording into an immediate hard browser abort.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Apply the short-page condition to generic challenge body-copy matches and add focused content-rich false-positive regression coverage without changing app-shell precedence or the persistent weak-script hydration grace.

Next step before merge

  • [P2] A narrow classifier-and-test repair can preserve the contributor’s core fix while removing the newly introduced generic-text false-positive path.

Security
Cleared: The focused TypeScript classifier and test changes add no concrete permission, secret, dependency, downloaded-code, or supply-chain concern.

Review findings

  • [P1] Constrain generic body text before treating it as a challenge — src/browser/actions/navigation.ts:623-626
Review details

Best possible solution:

Preserve app-shell precedence and persistent weak script-only detection, but apply the short-page requirement to generic verification-copy evidence; add a content-rich shell-less false-positive fixture and rerun the browser smoke surface.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source plus the submitted live CDP output establish the original script-only false positive, and the proposed verdict expression directly reproduces the new content-rich generic-body false positive without requiring a live account.

Is this the best way to solve the issue?

No as written. Positive evidence and app-shell precedence are the right direction, but generic body copy must inherit the short-page condition so the patch does not replace one false-positive trigger with another.

Full review comments:

  • [P1] Constrain generic body text before treating it as a challenge — src/browser/actions/navigation.ts:623-626
    saysVerifying makes phrases such as “just a moment” immediate strong evidence on any page where the listed app-shell selectors are absent, without applying the short-page condition used elsewhere in this classifier. A content-rich shell-less page, transient shell absence, or future selector drift can therefore hard-abort even though current main would not. Gate generic body-copy matches on the short-page condition and add a content-rich shell-less fixture containing the phrase. This was equally visible at the previously reviewed head and is a late discovery.
    Confidence: 0.94
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.93

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f3fbc067c9d8.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The redacted live CDP output demonstrates the exact healthy Work UI condition after the fix, and the production ledger reports no recurrence across 20 long runs; this proof does not cover the newly identified generic-text false positive but remains sufficient for the intended behavior.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🐚 platinum hermit and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The redacted live CDP output demonstrates the exact healthy Work UI condition after the fix, and the production ledger reports no recurrence across 20 long runs; this proof does not cover the newly identified generic-text false positive but remains sufficient for the intended behavior.
  • remove status: 📣 needs proof: Current PR status label is status: ⏳ waiting on author.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.

Label justifications:

  • P1: This availability-critical browser gate can still abort a normal signed-in workflow before prompt submission through the new generic-text path.
  • merge-risk: 🚨 availability: Merging the current classifier can turn ordinary shell-less page text into an immediate Cloudflare hard abort.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🐚 platinum hermit and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The redacted live CDP output demonstrates the exact healthy Work UI condition after the fix, and the production ledger reports no recurrence across 20 long runs; this proof does not cover the newly identified generic-text false positive but remains sufficient for the intended behavior.
  • proof: sufficient: Contributor real behavior proof is sufficient. The redacted live CDP output demonstrates the exact healthy Work UI condition after the fix, and the production ledger reports no recurrence across 20 long runs; this proof does not cover the newly identified generic-text false positive but remains sufficient for the intended behavior.
Evidence reviewed

Acceptance criteria:

  • [P1] pnpm vitest run tests/browser/pageActions.test.ts.
  • [P1] pnpm run typecheck.
  • [P1] pnpm exec oxlint.
  • [P1] pnpm exec oxfmt --check.

What I checked:

  • Blocking classifier defect: The proposed saysVerifying expression feeds directly into strong whenever the listed app-shell selectors are absent, without applying the short-page condition described by the PR or used for weak script evidence. (src/browser/actions/navigation.ts:623, 10fc2de1b86e)
  • Original bug is source-reproducible: Current main treats the challenge-platform script as sufficient evidence after a clean title, matching the reported healthy-page abort when Cloudflare bot-management injects that script. (src/browser/actions/navigation.ts:598, f3fbc067c9d8)
  • Real healthy-path proof: The updated PR body includes redacted live CDP output showing a healthy rendered ChatGPT page with hasAppShell: true and hasChallengeScript: true, plus a 20-run production-fork ledger reporting no Cloudflare abort recurrence. (src/browser/actions/navigation.ts:615, 10fc2de1b86e)
  • Regression coverage gap: The added fixtures cover a content-rich page carrying the script and a short page saying “just a moment,” but not a normal content-rich, shell-less page containing that generic phrase. (tests/browser/pageActions.test.ts:341, 10fc2de1b86e)
  • Feature-history provenance: Git history shows the current detector and central browser navigation area are predominantly carried by steipete, with Piotr Durlej also contributing repeated browser reliability and fail-closed behavior changes. (src/browser/actions/navigation.ts:598, 8b87a77417d1)
  • Current checks: GitGuardian plus macOS, Ubuntu, and Windows build jobs pass on the reviewed head; these checks do not cover the generic body-text false-positive fixture. (10fc2de1b86e)

Likely related people:

  • steipete: Authored and integrated the current detector and dominates history across the central browser navigation, reattach, and test paths. (role: feature owner; confidence: high; commits: 8b87a77417d1, ea6fd28d8a05, b91502c9c70b; files: src/browser/actions/navigation.ts, src/browser/index.ts, src/browser/reattach.ts)
  • Piotr Durlej: Has multiple merged browser reliability, login-gating, session, and fail-closed changes in the same navigation and browser-control surface. (role: recent area contributor; confidence: medium; commits: c64565dc6905, b1f77ad3e64a, 2453b89c389d; files: src/browser/actions/navigation.ts, src/browser/index.ts, src/browser/reattach.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-10T10:49:49.165Z sha 10fc2de :: needs real behavior proof before merge. :: none

@StartupBros

Copy link
Copy Markdown
Contributor Author

Added the requested redacted real-behavior proof to the PR body: a live CDP capture of a healthy GPT-5.6 Work-UI page carrying the challenge script (the false-positive input, correctly cleared with zero latency), the overnight production ledger on the fork build (20 reviews, zero cloudflare-challenge aborts), and the before/after contrast with the 2026-07-09 incident. @clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant