Firefox parity Phase 1: stealth + consent (v0.16.0)#4
Merged
Conversation
Fixes the two most agent-breaking Firefox gaps: headless bot-detection (navigator.webdriver=true) and consent dialogs never dismissed. Stealth: a POC measured stock Firefox-under-BiDi and falsified the plan's "port stealth.js verbatim" assumption — Chromium's STEALTH_SCRIPT is Chrome-shaped (window.chrome, Chrome plugins, SwiftShader WebGL) and would create a spoof tell worse than the one removed. Firefox's only real tell is navigator.webdriver, so it gets its own minimal script (webdriver + canvas noise) via script.addPreloadScript, headless-only. WEBDRIVER_PATCH and CANVAS_NOISE_PATCH are now exported from stealth.js so both engines share them (single-sources the canvas double-XOR fix). Consent: multilingual patterns extracted to consent-patterns.js (shared by the CDP and BiDi walkers). consent-firefox.js is a pure walker over the reconstructed nested AX tree, clicking via the existing pointerClick; wired into firefox-page.goto() behind the same consent!==false flag as the CDP path. Tests: consent-firefox unit tests (9, pure walker) + Firefox integration tests (webdriver hidden at parse time, no window.chrome spoof, consent auto-dismiss + a consent:false control that proves the test can fail). Full suite 209/209. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT
Version bump + docs for the Firefox anti-detection and consent auto-dismiss feature (committed in the preceding commit). CHANGELOG [0.16.0], context guide, and PRD known-gaps updated to reflect that consent + stealth now work on the Firefox/BiDi engine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT
A naive Object.defineProperty(navigator,'webdriver',…) hid the value but left
navigator.hasOwnProperty('webdriver')===true — a tell advanced anti-bot checks
(sannysoft "WebDriver New") detect, since real browsers keep webdriver on
Navigator.prototype. The shared WEBDRIVER_PATCH now deletes it off the
prototype, so navigator.webdriver is undefined AND hasOwnProperty/'in' are both
false, matching a stock browser. POC-verified on Chromium and Firefox.
Improves the Chromium engine too (shared patch). Regression tests added on both
paths (stealth.test.js + firefox.test.js). Found during live sannysoft
validation of the Firefox parity work.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MZpPPhwXmSfN1n7uX7RAxT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the Firefox/BiDi engine to practical parity with Chromium on the two
most agent-breaking gaps: headless bot-detection and cookie-consent walls.
First cut of the Firefox parity plan (
docs/01-product/firefox-parity-plan.md).What's in it
src/stealth-firefox.js, headless-only, via BiDiscript.addPreloadScript).A POC measured stock Firefox-under-BiDi and falsified the plan's "port
stealth.js verbatim" assumption — Chromium's script is Chrome-shaped
(
window.chrome, Chrome plugins, SwiftShader WebGL) and would have createda spoof tell on Firefox. Firefox's only real tell is
navigator.webdriver,so it gets a minimal script (webdriver + canvas noise).
WEBDRIVER_PATCH/CANVAS_NOISE_PATCHare exported fromstealth.jsand shared by both engines.src/consent-firefox.js). A pure walker over the reconstructednested AX tree, clicking via the existing
pointerClick. Multilingualpatterns extracted to
src/consent-patterns.js, shared by the CDP and BiDiwalkers. Runs after
goto()behindconsent !== false, same as CDP.navigator.webdriveron both engines. Found during livesannysoft validation: the naive override left a
hasOwnPropertytell. Theshared patch now deletes the getter off
Navigator.prototype, soundefined+hasOwnProperty/inbothfalse(matches a stock browser).Improves Chromium too.
Verification
tsc --noEmitclean.test/unit/consent-firefox.test.js(pure walker — scoping, priority,non-English, banner fallback, false-positive guard).
window.chromespoof, hasOwnProperty tell gone) + consent auto-dismiss with a
consent:falsecontrol that proves the test can fail; Chromium stealth extended for the
hardened patch.
navigator.webdriverhidden on sannysoft(trio: undefined + hasOwnProperty false + in false), canvas noise stable,
consent walker no false-positives on Google/Guardian, core snapshot fidelity
intact.
🤖 Generated with Claude Code