Skip to content

Hide navigator.webdriver via [Pref] gate in WebIDL #605

Open
barbatus wants to merge 1 commit intodaijro:mainfrom
barbatus:alex/hide-webdriver
Open

Hide navigator.webdriver via [Pref] gate in WebIDL #605
barbatus wants to merge 1 commit intodaijro:mainfrom
barbatus:alex/hide-webdriver

Conversation

@barbatus
Copy link
Copy Markdown

@barbatus barbatus commented May 3, 2026

Summary

patches/playwright/1-leak-fixes.patch already drops Navigator::Webdriver() to return false at the C++ level — but the webdriver attribute on Navigator is still exposed by WebIDL. Anti-bot platforms like FingerprintJS, DataDome and PerimeterX check the presence of navigator.webdriver

Description

Two new hunks added to 1-leak-fixes.patch:

  1. modules/libpref/init/StaticPrefList.yaml — declare a new static pref dom.webdriver.enabled (default false). Required because WebIDL [Pref="x.y.z"] resolves at build time to mozilla::StaticPrefs::x_y_z;

  2. dom/webidl/Navigator.webidl — add Pref="dom.webdriver.enabled" to the existing [Constant, Cached] extended-attribute bracket on the webdriver attribute. When the pref is false, the WebIDL binding code generator omits the attribute from the prototype entirely; 'webdriver' in navigator returns false, matching vanilla Firefox.

                                                                                                                                                                                                                                                        ## Type of Change                                               
    
  • Bug fix
  • New feature
  • Documentation update
  • Other

Testing

Quick local repro:

import asyncio                                                                                                                                                                                                                                                              
from camoufox.async_api import AsyncCamoufox                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                            
async def main():
    async with AsyncCamoufox(headless=True) as browser:                                                                                                                                                                                                                     
        page = await browser.new_page()                         
        await page.goto("about:blank")  
        present = await page.evaluate("'webdriver' in navigator")
        value   = await page.evaluate("navigator.webdriver")                                                                                                                                                                                                                
        print(f"  'webdriver' in navigator = {present}")
        print(f"  navigator.webdriver       = {value}")                                                                                                                                                                                                                     
                                                                
asyncio.run(main())                                                                                                                                                                                                                                                         

Fingerprint Report

This PR specifically targets a fingerprint surface (navigator.webdriver exposure). Build-tester run pending — happy to attach if a maintainer requests it. Expected delta on the score: positive (one fewer detectable signal).

Fingerprint report

(to be attached after build-tester run; happy to coordinate)

Checklist

  • I have linked a related issue above — none open; happy to file one if preferred
  • My changes are focused on a single logical change
  • I have added testing instructions which include the desired result
  • Service tests pass — temporarily out of service per template
  • Build test passes — pending; this PR adds a new static pref so the build must recompile WebIDLPrefs.cpp; would appreciate a maintainer's confirmation that the score improves

Currently 1-leak-fixes.patch makes Navigator::Webdriver() return false at
the C++ level, but the WebIDL attribute itself is still exposed —
``'webdriver' in navigator`` evaluates to ``true``. Anti-bot platforms
(FingerprintJS, datadome, etc.) check the *presence* of the attribute,
not just its value, so a false-but-present ``navigator.webdriver`` is
itself a bot signal that vanilla Firefox doesn't have.

Add two hunks:

1. ``modules/libpref/init/StaticPrefList.yaml`` — declare the static pref
   ``dom.webdriver.enabled`` (default false). Required for WebIDL
   ``[Pref="x.y.z"]`` to compile (resolves to
   ``mozilla::StaticPrefs::x_y_z``).

2. ``dom/webidl/Navigator.webidl`` — add ``Pref="dom.webdriver.enabled"``
   to the existing ``[Constant, Cached]`` extended-attribute bracket on
   the ``webdriver`` attribute. When the pref is false, the attribute is
   hidden entirely; ``'webdriver' in navigator`` returns false, matching
   vanilla Firefox.

The existing C++ revert (``Navigator::Webdriver() => false``) stays as
defense-in-depth in case anyone flips the pref at runtime.
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