Reproduction
In one long-lived skit process:
- Run a oneshot capture of a consent-bearing page with the prototype
custom_js clicker and click Agree.
- Run a later, unrelated oneshot capture of the same page without the clicker.
- The later session no longer shows the consent banner.
- As a control, run two consecutive captures without clicking; the banner remains in both.
This was reproduced across separate oneshot sessions in the same skit process.
Finding
The native Servo plugin creates one Servo with ServoBuilder::default().build() for the shared Servo thread, and reuses that process-wide Servo for all WebViews/instances. Servo creates its public HTTP resource threads and cookie jar when that Servo is built. The public HttpState owns an in-memory CookieStorage (servo-net ResourceChannelManager::create_http_states); it is not stored in InstanceState and is not reset when a WebView/oneshot instance is destroyed.
The plugin does not set Servo Opts.config_dir or temporary_storage, so there is no configured profile directory for this path. With the default config_dir: None, the cookie jar is process-wide for the shared Servo instance (and in-memory), not per capture instance.
Impact
A capture of an authenticated or consent-bearing page can influence a later unrelated capture in the same process. That is the same trust boundary the existing cross-session pixel-isolation tests were written to protect, but this leak is stateful rather than visual.
Suggested regression test
Use a local test origin with a consent endpoint/page whose response or DOM depends on a cookie. In one shared Servo/skit process, run: (a) a capture that sets the cookie, then an unrelated capture that asserts the banner/state is still present; and (b) two captures without setting the cookie as a control. Assert DOM/cookie state or response behavior, not pixels. The test should create fresh capture instances while retaining the shared Servo thread so it exercises the production scope.
The fix likely needs an explicit per-session storage/profile boundary or a documented isolation/reset operation; this issue is intentionally tracking the scope decision separately.
Reproduction
In one long-lived
skitprocess:custom_jsclicker and click Agree.This was reproduced across separate oneshot sessions in the same skit process.
Finding
The native Servo plugin creates one
ServowithServoBuilder::default().build()for the shared Servo thread, and reuses that process-wide Servo for all WebViews/instances. Servo creates its public HTTP resource threads and cookie jar when that Servo is built. The publicHttpStateowns an in-memoryCookieStorage(servo-netResourceChannelManager::create_http_states); it is not stored inInstanceStateand is not reset when a WebView/oneshot instance is destroyed.The plugin does not set Servo
Opts.config_dirortemporary_storage, so there is no configured profile directory for this path. With the defaultconfig_dir: None, the cookie jar is process-wide for the shared Servo instance (and in-memory), not per capture instance.Impact
A capture of an authenticated or consent-bearing page can influence a later unrelated capture in the same process. That is the same trust boundary the existing cross-session pixel-isolation tests were written to protect, but this leak is stateful rather than visual.
Suggested regression test
Use a local test origin with a consent endpoint/page whose response or DOM depends on a cookie. In one shared Servo/skit process, run: (a) a capture that sets the cookie, then an unrelated capture that asserts the banner/state is still present; and (b) two captures without setting the cookie as a control. Assert DOM/cookie state or response behavior, not pixels. The test should create fresh capture instances while retaining the shared Servo thread so it exercises the production scope.
The fix likely needs an explicit per-session storage/profile boundary or a documented isolation/reset operation; this issue is intentionally tracking the scope decision separately.