From 2e0adbde3381e0a49c8e79310425ddac5d449b65 Mon Sep 17 00:00:00 2001 From: feder-cr <85809106+feder-cr@users.noreply.github.com> Date: Thu, 21 May 2026 20:20:58 -0700 Subject: [PATCH] fix: id.sky.com tab crash on Windows headless=True (issue #18) Two-part fix for the wrapper-repo issue #18 (tab crash on id.sky.com and similar sites with cross-process navigation): Part 1 (this commit, wrapper-side): - _WIN_VIRT_DESKTOP_WORKAROUNDS adds security.sandbox.content.level=4. When the Chromium sandbox runs at content level >4 (default 6) it sets STARTUPINFO.lpDesktop=kAlternateWinstation for the content process, putting it on a different desktop than the browser process. Combined with our hidden alt-desktop (CreateDesktop) for headless windows hiding, that means cross-process navigations (Adobe AppMeasurement triggers a new origin -> new content process) can't reparent windows across desktops; the new content process exits cleanly and Playwright fires page.on('crash'). Lowering content sandbox to 4 keeps content processes on the parent's desktop. Level 4 still blocks file/registry/ network access; only the alt-winstation isolation is dropped, which is what the desktop bug requires. - README.md adds a Known Issues section pointing at issue #18 with the workaround (headless=False or Linux+Xvfb) for users on wrapper versions before firefox-7. Part 2 (separate commit in invisible-firefox@2e17b4871f93): - CanvasRenderingContext2D::GetImageDataArray moved the stealth pixel noise from rawData.mData (read-only DataSourceSurface::Map) to the JS Uint8ClampedArray's backing buffer. The original write to a read-only mapped surface segfaulted on GPU-backed canvases during browser.close() teardown. Verified end-to-end with InvisiblePlaywright headless=True + Evomi UK proxy on id.sky.com: page survives, no crash in loop, no crash at teardown. Reporter: @gamefireat123-eng. --- README.md | 18 ++++++++++++++++++ src/invisible_playwright/prefs.py | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/README.md b/README.md index 205617c..c95e4fa 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,24 @@ invisible_playwright version # wrapper and binary versions invisible_playwright clear-cache # remove all cached binaries ``` +## Known issues + +### `headless=True` on Windows can cause tab crashes on sites with heavy cross-process navigation + +Reported as [#18](https://github.com/feder-cr/invisible_playwright/issues/18) (`id.sky.com` and similar). On Windows, `headless=True` runs Firefox headed on a hidden alt-desktop created via `CreateDesktop`. Some sites (id.sky.com, anything else loading Adobe AppMeasurement in a way that triggers cross-process navigation) end up firing `page.on('crash')` after about 10 seconds. The cause is a window-parenting interaction between the alt-desktop and the GPU/content processes; the workaround is one of: + +```python +# Option A — keep the visible window (no alt-desktop) +with InvisiblePlaywright(seed=42, headless=False) as browser: + ... + +# Option B — run inside Xvfb on Linux (alt-desktop bug is Windows-only) +``` + +The visible window case works on every site we've tested. Linux + Xvfb is unaffected. + +--- + ## Related projects invisible_playwright takes a different angle than the major Firefox-hardening projects but stands on their shoulders: diff --git a/src/invisible_playwright/prefs.py b/src/invisible_playwright/prefs.py index 43ece27..496fd04 100644 --- a/src/invisible_playwright/prefs.py +++ b/src/invisible_playwright/prefs.py @@ -384,6 +384,21 @@ _WIN_VIRT_DESKTOP_WORKAROUNDS: Dict[str, Any] = { # Bugzilla refs: 1798091, 1524591, 1229829. Lowering the GPU sandbox to 0 # restores hardware compositor + functional WebGL on alt desktops. "security.sandbox.gpu.level": 0, + # Same root cause as above, content process side. Wrapper repo issue #18 + # (id.sky.com tab crash). Sandbox content level > 4 puts content processes + # on the sandbox's own kAlternateWinstation (see + # security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp line 1113-1114: + # `if (aSandboxLevel > 4) config->SetDesktop(kAlternateWinstation)`). + # Combined with our CreateDesktop alt-desktop, that puts browser process + # and content processes on DIFFERENT desktops. Cross-process navigation + # (Adobe AppMeasurement → new origin → new content process on a new + # desktop) then fails window parenting between parent and child → content + # process exits cleanly (exitCode=0, signal=null) and Playwright fires + # page.on('crash') ~10s after page load. Lowering content sandbox to 4 + # keeps content processes on the same desktop as the browser process, + # which is what we want here (and is still tight enough — level 4 + # blocks file/registry write, network calls, hardware access). + "security.sandbox.content.level": 4, }