feat(browse): allow CPU and network throttling for performance measurement

Adds Emulation.setCPUThrottlingRate and Network.emulateNetworkConditions to
CDP_ALLOWLIST.

Motivation: diagnosing a real "uploads take 1-2 minutes" report, the only
machine available was a fast developer workstation. Client-side processing
measured 1.4s where the user experienced minutes, so the conclusion had to be
reached arithmetically rather than observed. Throttling would have let the
measurement reproduce the reporter's conditions directly.

Both fit the existing posture rather than widening it:
  - Emulation already allows setDeviceMetricsOverride, clearDeviceMetricsOverride
    and setUserAgentOverride, which are equally mutating and scoped to the tab.
  - Neither method reads page content. setCPUThrottlingRate affects only timing;
    emulateNetworkConditions constrains traffic rather than inspecting it, so no
    request bodies, headers or cookies are exposed. Both are output: 'trusted'
    because they return no page-derived data.

scope 'tab' for both, matching the surrounding Emulation entries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
henbima
2026-08-17 10:18:00 -07:00
committed by Garry Tan
co-authored by Claude Fable 5
parent 0762fab809
commit 63ef693d02
2 changed files with 27 additions and 0 deletions
+14
View File
@@ -162,6 +162,20 @@ export const CDP_ALLOWLIST: ReadonlyArray<CdpAllowEntry> = Object.freeze([
output: 'trusted',
justification: 'Media type/feature override (prefers-color-scheme, prefers-reduced-motion, prefers-contrast, forced-colors) so a11y and dark-mode CSS branches are testable. Returns an empty result; no page content. NOTE: like setUserAgentOverride the override persists on the tab until cleared with an empty features array.',
},
{
domain: 'Emulation',
method: 'setCPUThrottlingRate',
scope: 'tab',
output: 'trusted',
justification: 'CPU slowdown multiplier on the active tab, for measuring performance on a realistic low-end client instead of the developer workstation. Same domain and mutating character as setDeviceMetricsOverride; affects only timing, reads nothing, exfiltrates nothing.',
},
{
domain: 'Network',
method: 'emulateNetworkConditions',
scope: 'tab',
output: 'trusted',
justification: 'Bandwidth/latency emulation on the active tab, for measuring page behaviour on a slow connection. Constrains traffic rather than reading it — no request bodies, headers or cookies are exposed.',
},
// ─── Page capture (output, not navigation) ─────────────────
{
domain: 'Page',
+13
View File
@@ -82,6 +82,19 @@ describe('CDP allowlist (T2: deny-default)', () => {
expect(e!.output).toBe('trusted');
});
it('CPU + network throttling are allowed, tab-scoped, trusted (#2602)', () => {
// Perf-measurement emulation (PR #2602 by @henbima): both constrain the
// tab's timing/traffic, read nothing, and return empty results — same
// posture argument as setEmulatedMedia (#2419) and setDeviceMetricsOverride.
for (const method of ['Emulation.setCPUThrottlingRate', 'Network.emulateNetworkConditions']) {
expect(isCdpMethodAllowed(method)).toBe(true);
const e = lookupCdpMethod(method);
expect(e).not.toBeNull();
expect(e!.scope).toBe('tab');
expect(e!.output).toBe('trusted');
}
});
it('untrusted-output methods cover the read-everything-attacker-controlled cases', () => {
// Anything that reads attacker-controlled strings (DOM/AX/CSS selectors)
// should be tagged untrusted so the envelope wraps the result.