Skip to content

fix(shard): drop fingerprint-only shims and keep WebRTC from failing bot checks - #115

Merged
kryptocodes merged 5 commits into
mainfrom
fix/shard-detection-hotfix
Oct 29, 2026
Merged

kryptocodes merged 5 commits into
mainfrom
fix/shard-detection-hotfix

Conversation

@kryptocodes

@kryptocodes kryptocodes commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

On the ShardX image, pages could detect the viewer tooling or fail bot checks:

  • The extension's fingerprint-only shims (geometry, API surface, media queries) stay off: the engine reports those values natively. The select picker, fullscreen, same-tab link and passkey shims are unchanged.
  • WebRTC: with BROWSER_PUBLIC_IP set to the proxy exit, WebRTC uses TCP only and reports that exit. Without it, Chrome's disable_non_proxied_udp policy applies. The engine's block policy failed some bot checks, which expect a public candidate.
  • The main image keeps its current behaviour.

Testing

  • Proxy: go vet, go test.
  • Local kind, through a residential proxy, proxy set after launch and with the exit IP at launch: the pages that were challenged before load without a challenge.

…ngerprint-only shims

The viewer emulator attached to every page from pod start, and the extension
replaced geometry, API-surface and media-query APIs in script. Pages can
detect both. On the ShardX image the emulator now waits for the first viewer
(MVD_EMULATOR_ON_VIEWER=1) and the fingerprint-only shims stay off
(MVD_FINGERPRINT_SHIMS=0), since the engine reports those values natively.
The select picker, fullscreen, same-tab link and passkey shims are unchanged,
and the main image keeps its current behaviour.
@reclaim-pr-agent

Copy link
Copy Markdown

Reclaim PR Agent review · run 122739189163

Result Head Blocking findings Ponytail suggestions Check
Changes required 0af2035cfa1d 1 1 View run
# Finding
1 images/minimal-vnc-desktop/extensions/proxy/injected.js:516: if (!fingerprintShims) { ... return; } executes before the fullscreen, same-tab navigation, and select-picker shims.…
# Ponytail suggestion
1 images/minimal-vnc-desktop/proxy/emulate.go:L588: shrink: defensive nil/awake guard in wake. Call e.wakeOnce.Do(func() { close(e.awake) }) directly; newEmulator always initializes…
Full findings and Ponytail review
  • images/minimal-vnc-desktop/extensions/proxy/injected.js:516: if (!fingerprintShims) { ... return; } executes before the fullscreen, same-tab navigation, and select-picker shims. Consequently, the Shard image's new default of MVD_FINGERPRINT_SHIMS=0 returns from the injected script and disables those functional shims, despite mobile emulation remaining enabled. This breaks expected viewer behavior (for example, native fullscreen is again rendered against the full emulated screen and can be clipped in the magnified viewer; native select popups and new-tab links also bypass their compatibility handling). Smallest safe fix: do not return at this point; scope fingerprintShims conditionals only around the geometry/API-surface/media-query shim sections later in the script, leaving fullscreen, link, select-picker, and passkey logic active whenever emulationEnabled is true.

Ponytail suggestions:

  • images/minimal-vnc-desktop/proxy/emulate.go:L588: shrink: defensive nil/awake guard in wake. Call e.wakeOnce.Do(func() { close(e.awake) }) directly; newEmulator always initializes awake.

net: -3 lines possible.

@reclaim-pr-agent

Copy link
Copy Markdown

Reclaim PR Agent review · run 122862822479

Result Head Blocking findings Ponytail suggestions Check
Changes required 371f34d192ee 1 2 View run
# Finding
1 images/minimal-vnc-desktop/extensions/proxy/injected.js: when Shard writes POPCORN_FINGERPRINT_SHIMS = false, the new if (!fingerprintShims) { ... return; } exits before the…
# Ponytail suggestion
1 images/minimal-vnc-desktop/proxy/emulate_test.go:L18,L26,L43: delete: MVD_EMULATOR_OFF setup is not read by newEmulator or the code exercised by these tests. Nothing.
2 images/minimal-vnc-desktop/proxy/emulate_test.go:L38-L39: delete: Extra connect and wake calls have no assertion or observable effect after the first viewer wake is verified.…
Full findings and Ponytail review
  • images/minimal-vnc-desktop/extensions/proxy/injected.js: when Shard writes POPCORN_FINGERPRINT_SHIMS = false, the new if (!fingerprintShims) { ... return; } exits before the fullscreen, same-tab navigation, and in-page select-picker shims. Those shims are below the return and are required independently of fingerprint masking while emulation remains enabled. Thus the new Shard default (MVD_FINGERPRINT_SHIMS=0) disables the functional mobile compatibility behavior that the PR description says remains enabled. Smallest safe fix: do not return for !fingerprintShims; instead, conditionally skip only the later geometry/API/media-query fingerprint-shim sections, allowing fullscreen, navigation, and select-picker setup to execute.

Ponytail suggestions:

  • images/minimal-vnc-desktop/proxy/emulate_test.go:L18,L26,L43: delete: MVD_EMULATOR_OFF setup is not read by newEmulator or the code exercised by these tests. Nothing.
  • images/minimal-vnc-desktop/proxy/emulate_test.go:L38-L39: delete: Extra connect and wake calls have no assertion or observable effect after the first viewer wake is verified. Nothing.

net: -5 lines possible.

@reclaim-pr-agent

Copy link
Copy Markdown

Reclaim PR Agent review · run 123023847435

Result Head Blocking findings Ponytail suggestions Check
Changes required fa0a26bc63e6 2 1 View run
# Finding
1 images/minimal-vnc-desktop/extensions/proxy/injected.js: the new if (!fingerprintShims) { ... return; } is placed before the fullscreen, same-tab navigation, and in-page select-…
2 images/shard-vnc-desktop/start-shard.mjs: replacing the SDK launch option webrtc: 'block' with --force-webrtc-ip-handling-policy=disable_non_proxied_udp re-enables WebRTC TCP…
# Ponytail suggestion
1 images/minimal-vnc-desktop/proxy/emulate.go:L589: yagni: nil/zero-value guards in wake despite every caller using a constructed emulator. `e.wakeOnce.Do(func() { close(e.awake)…
Full findings and Ponytail review
  • images/minimal-vnc-desktop/extensions/proxy/injected.js: the new if (!fingerprintShims) { ... return; } is placed before the fullscreen, same-tab navigation, and in-page select-picker shims. Shard now writes POPCORN_FINGERPRINT_SHIMS = false by default, so this return disables those functional emulation shims even though emulation remains enabled. This directly contradicts the stated behavior and breaks mobile viewer interactions/layout handling. Smallest safe fix: do not return when fingerprint shims are disabled; gate only the geometry/API/media-query shim sections individually, leaving fullscreen, navigation, and select-picker shims active whenever emulationEnabled is true.
  • images/shard-vnc-desktop/start-shard.mjs: replacing the SDK launch option webrtc: 'block' with --force-webrtc-ip-handling-policy=disable_non_proxied_udp re-enables WebRTC TCP traffic. That flag restricts non-proxied UDP only; it does not block non-proxied TCP/TURN WebRTC connections. A page can request a TCP TURN relay controlled by the page/operator and observe the container/host network source address, bypassing the session proxy and leaking network identity. Smallest safe fix: retain webrtc: 'block', or use an equivalent configuration that blocks all non-proxied WebRTC transports—not only UDP—before removing the SDK-level block.

Ponytail suggestions:

  • images/minimal-vnc-desktop/proxy/emulate.go:L589: yagni: nil/zero-value guards in wake despite every caller using a constructed emulator. e.wakeOnce.Do(func() { close(e.awake) }).

net: -3 lines possible.

…iewer wait

With BROWSER_PUBLIC_IP set to the proxy exit, WebRTC uses TCP only and
reports that exit as its public address. Without it, Chrome's
disable_non_proxied_udp policy applies, since some bot checks fail when no
public candidate appears at all.

The emulator attaches at startup again: with the fingerprint shims off,
waiting for the first viewer made no difference.
@kryptocodes kryptocodes changed the title fix(shard): keep pages unattached until a viewer connects and drop fingerprint-only shims fix(shard): drop fingerprint-only shims and keep WebRTC from failing bot checks Oct 29, 2026
@kryptocodes

Copy link
Copy Markdown
Contributor Author

On the merge gate findings:

  1. injected.js early return: the fullscreen, window.open and select-picker shims are installed before it (lines 125, 181, 235), so they stay on. Only the fingerprint-only shims after it are skipped.
  2. WebRTC: webrtc: 'block' is not restored, because it fails bot checks that expect a public candidate. When the proxy exit is known at launch (BROWSER_PUBLIC_IP), WebRTC now uses TCP only and reports that exit, so no candidate leaves on the host route. Without it, Chrome's disable_non_proxied_udp policy applies, as before.

The wake() suggestion no longer applies: the viewer wait is removed.

@reclaim-pr-agent

Copy link
Copy Markdown

Reclaim PR Agent review · run 123404055118

Result Head Blocking findings Ponytail suggestions Check
Changes required c6b9707d12d2 2 1 View run
# Finding
1 images/minimal-vnc-desktop/extensions/proxy/injected.js: When Shard's new default writes POPCORN_FINGERPRINT_SHIMS = false, the new early return runs before the fullscreen,…
2 images/shard-vnc-desktop/start-shard.mjs: For the normal no-BROWSER_PUBLIC_IP case, this replaces the prior SDK-level webrtc: 'block' with `--force-webrtc-ip-handling-…
# Ponytail suggestion
1 images/shard-vnc-desktop/start-shard.mjs:L12-15: yagni: MVD_FINGERPRINT_SHIMS is a per-image toggle for a value this image always knows. Always write POPCORN_FINGERPRINT_SHIMS =…
Full findings and Ponytail review
  • images/minimal-vnc-desktop/extensions/proxy/injected.js: When Shard's new default writes POPCORN_FINGERPRINT_SHIMS = false, the new early return runs before the fullscreen, same-tab navigation, and in-page select-picker shims. Those shims are independently required whenever emulation is enabled, so the default Shard configuration disables the functional behavior the PR explicitly says remains on. Smallest safe fix: do not return when fingerprint shims are disabled; instead, condition only the geometry/API/media-query shim sections on fingerprintShims, leaving the functional shims and ready event active.
  • images/shard-vnc-desktop/start-shard.mjs: For the normal no-BROWSER_PUBLIC_IP case, this replaces the prior SDK-level webrtc: 'block' with --force-webrtc-ip-handling-policy=disable_non_proxied_udp. That Chrome policy only disallows non-proxied UDP; it does not disable WebRTC or non-proxied TCP. Pages can therefore regain WebRTC/TCP connectivity on the direct route before an extension-configured proxy is applied, creating an egress/IP-exposure regression from the previously blocked behavior. Smallest safe fix: retain webrtc: 'block' when BROWSER_PUBLIC_IP is absent, and enable the TCP-only/public-IP SDK configuration only when a verified public proxy exit is available at launch.

Ponytail suggestions:

  • images/shard-vnc-desktop/start-shard.mjs:L12-15: yagni: MVD_FINGERPRINT_SHIMS is a per-image toggle for a value this image always knows. Always write POPCORN_FINGERPRINT_SHIMS = false and remove the environment variable, validation, and README option.

net: -6 lines possible.

@reclaim-pr-agent

Copy link
Copy Markdown

Reclaim PR Agent review · run 123422830646

Result Head Blocking findings Ponytail suggestions Check
Changes required 7b2e04621545 1 0 View run
# Finding
1 images/shard-vnc-desktop/start-shard.mjs — When BROWSER_PUBLIC_IP is absent (explicitly the normal case when the proxy is set after launch), this change removes `webrtc:…
Full findings and Ponytail review
  • images/shard-vnc-desktop/start-shard.mjs — When BROWSER_PUBLIC_IP is absent (explicitly the normal case when the proxy is set after launch), this change removes webrtc: 'block' and substitutes --force-webrtc-ip-handling-policy=disable_non_proxied_udp. That policy restricts non-proxied UDP only; it does not block direct TCP WebRTC/ICE traffic. A page can use TCP TURN/ICE and cause a connection from the container’s default route, exposing the host/pod egress IP to the page-controlled endpoint despite the later extension proxy. This is a regression from the previous no-WebRTC behavior and a concrete proxy/privacy leak. Smallest safe fix: retain webrtc: 'block' whenever BROWSER_PUBLIC_IP is not available; only enable the tcp_only/webrtcPublicIp path when a verified proxy exit is supplied at launch.

Ponytail: Lean already. Ship.

@kryptocodes
kryptocodes merged commit 960f57b into main Oct 29, 2026
18 checks passed
@kryptocodes
kryptocodes deleted the fix/shard-detection-hotfix branch October 29, 2026 11:42
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.

3 participants