From 7a1ca904164ff01625aeed2d39078496adef2f1a Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Mon, 1 Jun 2026 13:41:49 +0900 Subject: [PATCH] =?UTF-8?q?fix(stealth):=20webdriver=20=3D=20false=20(not?= =?UTF-8?q?=20undefined)=20=E2=80=94=20never=20delete=20the=20property?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The webdriver patch deleted navigator.webdriver, leaving it `undefined`. Real Chrome reports `false`, so `undefined` is itself a detection tell, and deleting it also removes the native `false` that Emulation.setAutomationOverride sets. Now we rely on setAutomationOverride for a native (undetectable) `false` and only force `false` via a getter as a fallback when webdriver is still `true` (older Chrome without that override) — never delete it. Verified: FullLaunch headless now reports navigator.webdriver === false (boolean), consistently. --- cli/src/native/stealth_scripts.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/cli/src/native/stealth_scripts.js b/cli/src/native/stealth_scripts.js index 5cfd420..7eb267b 100644 --- a/cli/src/native/stealth_scripts.js +++ b/cli/src/native/stealth_scripts.js @@ -1,14 +1,29 @@ const __abStealth = { locale: "en-US", languages: ["en-US", "en"], allowWebGLContextFallback: false }; (function(){ - const removeWebdriver = (target) => { + // Prefer the CDP-level automation override (Emulation.setAutomationOverride), + // which makes navigator.webdriver report `false` NATIVELY — undetectable by + // lie-detection (creepjs). Only intervene when webdriver is still truthy + // (e.g. older Chrome without that override) and force it to FALSE. + // + // Never `delete` webdriver: real Chrome reports `false`, so `undefined` is + // itself a tell, and deleting it removes the native `false` the override set. + const forceWebdriverFalse = (target) => { if (!target) return; - try { delete target.webdriver; } catch {} + try { + if (target.webdriver === true) { + Object.defineProperty(target, 'webdriver', { + get: () => false, + configurable: true, + enumerable: false, + }); + } + } catch {} }; - removeWebdriver(navigator); - removeWebdriver(Object.getPrototypeOf(navigator)); - removeWebdriver(Navigator.prototype); + forceWebdriverFalse(navigator); + forceWebdriverFalse(Object.getPrototypeOf(navigator)); + forceWebdriverFalse(Navigator.prototype); if (typeof WorkerNavigator !== 'undefined') { - removeWebdriver(WorkerNavigator.prototype); + forceWebdriverFalse(WorkerNavigator.prototype); } })(); (function(){