Investigating the Selenium Chrome mode of Open Bullet 2
This is the fourth article of the series about Open Bullet 2. In the previous article, we studied the Puppeteer mode of Open Bullet. We showed that Open Bullet 2 relies on PuppeteerExtraSharp, which can be detected because of inconsistencies, such as device signals that are different in a web worker compared to the main JS execution context
In this article, we focus on the Selenium Chrome mode of Open Bullet 2. We create a simple bot based on it to study its fingerprint and see how it can be detected.
Creating a Selenium-Chrome-based bot in Open Bullet 2
First, we need to set the Chrome path for Selenium in
the RuriLib Settings
panel, cf the screenshot below.
Then, we create a new configuration and edit it using
the Stacker
panel. The configuration looks as follows:
Our Selenium-Chrome-based bot does the following:
- Create a browser instance using the
Selenium
function block;
- Navigate to https://deviceandbrowserinfo.com/are_you_a_bot;
- We wait 2s;
- Get the value of
window.fingerprint
using theExecute JS
block;
- Get the value of the bot detection using the
Execute JS
block;
- Close the browser instance.
We see that by default, Open Bullet 2 used with Selenium Chrome (headless) is properly detected as a bot.
{
"isBot": true,
"details": {
"hasBotUserAgent": true,
"hasWebdriverTrue": true,
"hasWebdriverInFrameTrue": true,
"hasInconsistentChromeObject": false,
"isPhantom": false,
"isNightmare": false,
"isSequentum": false,
"isSeleniumChromeDefault": false,
"isHeadlessChrome": false,
"isWebGLInconsistent": false,
"isAutomatedWithCDP": true,
"isAutomatedWithCDPInWebWorker": false,
"hasInconsistentClientHints": false,
"hasInconsistentGPUFeatures": false,
"isIframeOverridden": false,
"hasInconsistentWorkerValues": false
}
}
Open bullet is detected for several reasons:
- By default, the user agent is the one of headless Chrome:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/127.0.6533.119 Safari/537.36
;
- We observe the presence
navigator.webdriver = true
;
- We detect side effects of CDP automation (Chrome Devtools Protocol)
Note that we could have made our Selenium Chrome bot non-headless, which would have avoid the user agent detection, but wouldn’t have impacted the other signals.
Can we make the bot stealthier?
In a previous article, we already discussed how we can adapt a vanilla Selenium Chrome to make it more difficult to detect. In particular, here we’d like to modify it to:
- Get rid of the Headless Chrome user agent;
navigator.webdriver = true
The usual way to change the user agent is to provide the
--user-agent=
flag when starting Chrome. Regarding navigator.webdriver
, we can
disable it using the --disable-blink-features=AutomationControlled
flag.
Open Bullet 2 provides two mechanisms to provide arguments to the browser:
- In the
Config settings
panel, cf screenshot below, where there is aCommand line arguments
option.
- In
Extra Cmd Line Args
of theOpen Browser
block.
None of these solutions worked. It seems that Open Bullet 2 doesn’t handle the command line arguments string properly, cf below where we see that the two flags are inserted into the user agent. Note that I tried with/without quotes, escaping characters, etc. None of the options worked.
{
"userAgent":"testuseragent --disable-blink-features=AutomationControlled",
"platform":"MacIntel",
...
}
I think there might be a bug in the way Open Bullet 2 handles these additional command line arguments. If we look at the .NET code that handle the command line arguments, we see the following:
It passes the args
string to
chromeop.AddArgument
. I’m not a .NET expert, but according to Claude Sonnet (LLM),
“The AddArgument
method is used to add a single command-line argument to
the ChromeOptions object.”
However, here, we’re trying to add ≥ 2 arguments:
- The first to change the user agent;
- The second to remove
navigator.webdriver = true
.
Another possibility could be to change the user agent and
remove navigator.webdriver
from JavaScript. However, it may have detectable side effects, and I
decided not to pursue in this direction. At some point, certain changes to avoid detection are to cumbersome
to do from Open Bullet 2 and require access to the code of the underlying framework (here Selenium).
Similarly, it would have been difficult/cumbersome to lie about the CDP detection.
Conclusion
Contrary to the puppeteer mode of Open Bullet 2 that relies on PuppeteerExtraSharp, a modified version of Puppeteer, the Selenium mode uses the vanilla Selenium library, which doesn’t have any anti-detect feature.
Thus, when used in Headless mode with Selenium, Open
Bullet 2 can be easily detected using a wide range of techniques, such as the detection of
navigator.webdriver = true
and the side effects of the CDP automation.