Skip to content

Stop leaking the API key; make --fingerprint apply the fingerprint - #8

Merged
jehrr merged 1 commit into
mainfrom
fix/family-wide-defects
Sep 9, 2026
Merged

Stop leaking the API key; make --fingerprint apply the fingerprint#8
jehrr merged 1 commit into
mainfrom
fix/family-wide-defects

Conversation

@jehrr

@jehrr jehrr commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Four defects found while building the newest repo in this family against the same shared core. All present here unchanged.

🔴 The API key could reach a log

fingerprint_client.py sends the key as a query parameter, and requests puts the full URL — query string included — into the text of HTTPError and of every connection error. A 400 from the fingerprint endpoint therefore prints a live key. It did, on a real call.

Everything raised or logged from that module, and from captcha_solver.py's v1 polling GET (the other place the key rides in a URL rather than a body or header), now goes through a redactor. The endpoint and status survive; the key becomes key=***. The other key-carrying calls were checked and are safe — createTask/getTaskResult use the JSON body.

--fingerprint was applying almost none of the fingerprint

What Was Now
User agent never set — read from userAgent.value, a key the API returns in neither format userAgent.userAgent / data.ua
Locale f"en-{country}"en-DE for a German fingerprint intl.contentLocalede-DE
Timezone not applied at all intl.timeZone
Window size guessed as screen height − 120 the response's own outerWidth/outerHeight

The UA one matters most: the flag left the browser on its own user agent while replacing the screen and locale around it — a fingerprint's identity wearing the local Chromium's UA, which is exactly the mismatch this family warns about when it says never to stack a second identity on a remote browser.

Verified against a live browser on the newest repo: with a German Windows fingerprint applied, the page reports that UA, de-DE, Europe/Berlin and a window smaller than its screen.

The documented --tags example always returned 400

"Windows,Chrome,Desktop" is rejected every time. Measured against the live API:

Accepted Rejected (400)
Windows, Microsoft Windows, Android Chrome, Desktop, Mobile, Unknown, and every combination with any separator

tags takes one OS-family value. The plural name — and a returned fingerprint's own multi-valued data.tags — are what make the list form look plausible.

The Docker image was broken on every invocation

Including --help, its own CMD. The Dockerfile COPYs an explicit module list (correct — the image should carry no test suite and no stray .env) and the list had fallen behind: proxy_pool.py was missing while the entrypoint imports it at module level. Nothing noticed, because CI never builds the image.

Verified by assembling the image's exact file set in a temporary directory and running the entrypoint from there; no container runtime was available here.

Deliberately NOT changed: the captcha detectors

The newest repo had to stop treating extension-injected markers as challenges, because the Scraping Browser's auto-solve extension puts cf-turnstile into every page it loads. This repo's marker set contains nothing that extension injects — checked — so the same guard here would be dead code. The hazard is recorded in the family CLAUDE.md instead, for whoever broadens a marker set next.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Wp7ctnpMGb5gi67Dco7C5V

Four defects, all found while building the newest repo in this family
against the same shared core, and all present here unchanged.

The API key could reach a log
------------------------------
fingerprint_client.py sends the key as a QUERY parameter, and `requests` puts
the full URL — query string included — into the text of HTTPError and of
every connection error. A 400 from the fingerprint endpoint therefore prints
a live key. It did, on a real call.

Everything raised or logged from that module, and from captcha_solver.py's v1
polling GET (the other place the key rides in a URL rather than a body or a
header), now goes through a redactor first. The endpoint and status survive:
which call failed is the useful half and is not the secret. The other
key-carrying calls were checked and are safe — createTask/getTaskResult put
it in the JSON body.

--fingerprint was applying almost none of the fingerprint
----------------------------------------------------------
  * The USER AGENT was never set. It was read from `userAgent.value`, a key
    the API returns in NEITHER format — it is `userAgent.userAgent` in
    chromium and `data.ua` in raw. So the flag left the browser on its own UA
    while replacing the screen and locale around it: a fingerprint's identity
    wearing the local Chromium's user agent, which is the mismatch this
    family warns about when it says never to stack a second identity on a
    remote browser.
  * The LOCALE contradicted the fingerprint. Built as f"en-{country}", giving
    "en-DE" for a German fingerprint where the response says "de-DE".
  * The TIMEZONE was not applied at all, though the response states it and
    Playwright can set it.
  * The WINDOW SIZE was guessed as `screen height - 120` when the response
    states its own outerWidth/outerHeight.

Verified against a live browser on the newest repo: with a German Windows
fingerprint applied, the page reports that UA, de-DE, Europe/Berlin and a
window smaller than the screen — every one matching the fingerprint rather
than the host.

The documented --tags example always returned 400
--------------------------------------------------
"Windows,Chrome,Desktop" is rejected every time. Measured against the live
API: `tags` takes ONE OS-family value. Windows, Microsoft Windows and Android
are accepted; Chrome, Desktop, Mobile and Unknown are not, and no combination
is accepted with any separator. The plural name, and a returned fingerprint's
own multi-valued data.tags, are what make the list form look plausible.

The Docker image was broken on every invocation
------------------------------------------------
Including `--help`, its own CMD. The Dockerfile COPYs an explicit module list
— correct, so the image carries no test suite and no stray .env — and the
list had fallen behind: proxy_pool.py was missing while the entrypoint
imports it at module level. Nothing noticed, because CI never builds the
image.

Verified by assembling the image's exact file set in a temporary directory
and running the entrypoint from there; no container runtime was available.

Not changed: the captcha detectors
-----------------------------------
The newest repo in this family had to stop treating extension-injected
markers as challenges, because the Scraping Browser's auto-solve extension
puts `cf-turnstile` into every page it loads. This repo's marker set does not
contain anything that extension injects, so the same guard here would be dead
code. The hazard is recorded in the family CLAUDE.md instead, for whoever
broadens a marker set next.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wp7ctnpMGb5gi67Dco7C5V
@jehrr
jehrr merged commit 37b2ffe into main Sep 9, 2026
6 checks passed
@jehrr
jehrr deleted the fix/family-wide-defects branch September 9, 2026 16:13
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