Skip to content

feat: classify grok-web Cloudflare anti-bot blocks + gated browser-backed cf_clearance path (#8019) - #8241

Merged
diegosouzapw merged 1 commit into
release/v3.8.49from
feat/8019-grok-web-stealth-browser
Jul 23, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.49from
feat/8019-grok-web-stealth-browser

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

Ports the existing stealth-browser / cf_clearance infra (already live for claude-web and duckduckgo-web) to grok-web, in two parts.

Part 1 (primary, fully unit-tested, no browser dependency). grok-web.ts already imported isCloudflareChallenge from grokTlsClient.ts but never called it — so a Cloudflare anti-bot block ("Request rejected by anti-bot rules") was misclassified as a generic authentication_error, the exact complaint in #8019. A new pure helper classifyGrokNullBodyError(status, text) now distinguishes:

  • Cloudflare challenge body → type: "cloudflare_challenge", code: "cf_mitigated_challenge", with an actionable message (cf_clearance is pinned to IP+TLS+UA and can't be replayed from a datacenter egress; use a residential IP or the official xAI API).
  • 401/403 with a normal body → authentication_error (unchanged behavior, re-paste SSO cookie).
  • 429 → rate_limit_error (regression guard, unchanged behavior).
  • anything else → upstream_error (unchanged).

Part 2 (secondary, gated; real-world effectiveness is VPS-gated). Behind the existing OMNIROUTE_BROWSER_POOL / WEB_COOKIE_USE_BROWSER opt-in gate (same env vars already used by claude-web.ts / duckduckgo-web.ts), on a detected Cloudflare challenge the executor now attempts ONE browser-backed cf_clearance refresh via the provider-agnostic browser pool (browserPool.ts → new open-sse/services/grokClearance.ts helper) and retries tlsFetchGrok once with the fresh cookie injected. No new Turnstile solver — claudeTurnstileSolver.ts is claude.ai-specific and out of scope; this reuses the same generic pool primitive already live for the other two providers. On any acquisition/retry failure it falls through to the Part-1 cloudflare_challenge error — never throws.

Gate stays off by default (env var unset). Nothing changes for existing grok-web users who don't opt in.

Files changed

  • open-sse/executors/grok-web.ts — classification + gated retry wiring
  • open-sse/services/grokClearance.ts (new) — shouldUseGrokBrowserBacked() gate + acquireFreshGrokClearance() (test-seam injectable, mirrors browserBackedChat.ts's override pattern)
  • tests/unit/grok-web-cloudflare-classification.test.ts (new) — 16 tests covering pure classification, executor wiring, and gated retry (gate OFF / gate ON+success / gate ON+acquisition-failure / gate ON+retry-still-challenged), all with a mocked TLS client and mocked browser acquisition — no real network/browser in CI
  • changelog.d/features/8019-grok-web-cloudflare-classification.md

Testing

  • node --import tsx/esm --test tests/unit/grok-web-cloudflare-classification.test.ts — 16/16 green
  • node --import tsx/esm --test tests/unit/grok-web.test.ts tests/unit/grok-web-executor-split.test.ts — 65/65 green (no regression)
  • npm run typecheck:core / npm run typecheck:noimplicit:core — clean on changed files (pre-existing unrelated errors on combo.ts/usageTracking.ts/cliRuntime.ts confirmed identical on origin/release/v3.8.49, not touched by this PR)
  • npx eslint --suppressions-location config/quality/eslint-suppressions.json on changed files — clean
  • npm run check:complexity-ratchets — flags a pre-existing regression (2156 vs baseline 2130) that is identical on a clean origin/release/v3.8.49 checkout with none of this PR's changes applied (verified in an isolated detached worktree) — confirmed base-red, not introduced here. My new/edited functions in grok-web.ts do not appear in the ESLint complexity report at all.
  • node scripts/check/check-test-discovery.mjs — new test file collected, OK
  • node scripts/check/check-file-size.mjs — OK, grok-web.ts within baseline
  • npm run check:cycles — OK, no new cycles

Live check needed before Part 2 is fully trusted

Part 2's real-world effectiveness (whether the browser pool actually mints a usable cf_clearance from a Cloudflare-flagged datacenter egress) needs a live VPS check per Hard Rule #18: deploy to 192.168.0.15, connect a grok-web sso cookie from a flagged egress, set OMNIROUTE_BROWSER_POOL=on, issue a chat request, and confirm either a successful recovery or the distinct cloudflare_challenge error. Part 1 (the classification fix) is fully proven by the unit tests above and needs no live check.

Closes #8019

@diegosouzapw diegosouzapw added the hold-vps PR verde, merge aguardando validação live (release-drain) label Jul 23, 2026
@diegosouzapw
diegosouzapw merged commit 9a3b605 into release/v3.8.49 Jul 23, 2026
10 checks passed
@diegosouzapw
diegosouzapw deleted the feat/8019-grok-web-stealth-browser branch July 23, 2026 13:05
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…cked cf_clearance path (diegosouzapw#8019) (diegosouzapw#8241)

Co-authored-by: Probe Test <probe@example.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…cked cf_clearance path (diegosouzapw#8019) (diegosouzapw#8241)

Co-authored-by: Probe Test <probe@example.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold-vps PR verde, merge aguardando validação live (release-drain)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(providers): grok-web anti-bot — add stealth-browser (CloakBrowser) validation path

1 participant