Skip to content

fix: use curl_cffi to bypass Cloudflare TLS fingerprinting#1

Open
gimmelovej wants to merge 1 commit into
offseq:mainfrom
gimmelovej:fix/cloudflare-tls-fingerprint
Open

fix: use curl_cffi to bypass Cloudflare TLS fingerprinting#1
gimmelovej wants to merge 1 commit into
offseq:mainfrom
gimmelovej:fix/cloudflare-tls-fingerprint

Conversation

@gimmelovej

Copy link
Copy Markdown

Fix Cloudflare 403 blocks by replacing urllib with curl_cffi

Problem

The current implementation uses Python's built-in urllib to make requests to x.com. While functional in theory, urllib produces a TLS handshake fingerprint that is easily identifiable as non-browser traffic. Cloudflare's bot detection system flags this fingerprint and responds with a 403 Forbidden error before the request even reaches X's API — regardless of whether valid cookies (auth_token, ct0) are provided.

This makes the tool effectively unusable for many users, even when they supply a fully authenticated browser session.

Error observed:

Error: Request failed: 403 Forbidden: <!DOCTYPE html>...<title>Attention Required! | Cloudflare</title>...

Root Cause

Cloudflare performs TLS fingerprinting (also known as JA3/JA4 fingerprinting) on incoming connections. Python's urllib and even requests present a TLS ClientHello that differs significantly from what real browsers (Chrome, Firefox) send — in cipher suites, extensions order, and other handshake parameters. Cloudflare uses this signal to classify the connection as automated traffic and blocks it at the edge, before any cookie or authentication header is evaluated.

Solution

This PR replaces urllib with curl_cffi, a Python library that wraps libcurl with support for browser TLS impersonation. By setting impersonate="chrome124", the library produces a TLS handshake indistinguishable from Chrome 124, allowing requests to pass through Cloudflare's bot detection layer.

All existing behavior is preserved:

  • Cookie handling (--cookie, --cookie-file)
  • Guest token activation
  • CSRF token (ct0) extraction
  • Bearer token resolution
  • Pagination, rate limiting, JSON output, quiet mode — all unchanged

The only structural change is that urllib.request calls are replaced by a persistent curl_cffi.requests.Session, which also improves performance via connection reuse.

Changes

  • xcompare.py: replaced urllib-based HTTP calls with curl_cffi.requests.Session(impersonate="chrome124")
  • New dependency: curl_cffi (available on PyPI)

New Requirement

Users will need to install curl_cffi before running the tool:

pip install curl_cffi

It is recommended to add this to the README under Prerequisites.

Testing

Tested against two public X accounts that previously returned 403 Forbidden with the original urllib implementation. After this change, both accounts resolved correctly and follower data was fetched successfully.

Notes

  • curl_cffi is actively maintained and supports Windows, macOS, and Linux
  • The impersonation target can be updated (e.g. chrome131) if future Cloudflare rules require a newer fingerprint
  • This does not affect users who were not experiencing the Cloudflare block — the behavior is identical from their perspective

So much depends upon a red wheelbarrow

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.

1 participant