@percy/nightwatch 2.2.1-beta.1 → 2.2.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46,10 +46,13 @@ module.exports = class PercySnapshotCommand {
46
46
  // Readiness gate — runs before serialize when CLI supports it.
47
47
  const readinessDiagnostics = await waitForReady(this.api, options, utils, log);
48
48
 
49
- // Thread domScript + log through ctx so concurrent percySnapshot calls
49
+ // Serialize and capture the DOM. Merge .percy.yml config with per-snapshot
50
+ // options (per-call wins) before handing them to serialize.
51
+ // domScript + log are threaded through so concurrent percySnapshot calls
50
52
  // (parallel workers in the same Node process) don't race on shared
51
53
  // module-level state.
52
- let { domSnapshot, url } = await captureDOM(this.api, options, utils, domScript, log);
54
+ const mergedOptions = utils.mergeSnapshotOptions(options);
55
+ let { domSnapshot, url } = await captureDOM(this.api, mergedOptions, utils, domScript, log);
53
56
 
54
57
  // Attach readiness diagnostics so the CLI can log timing and pass/fail
55
58
  if (readinessDiagnostics && domSnapshot && typeof domSnapshot === 'object' && !Array.isArray(domSnapshot)) {
@@ -63,8 +66,24 @@ module.exports = class PercySnapshotCommand {
63
66
  ...snapshotOptions
64
67
  } = options;
65
68
 
69
+ // Sanitize caller-supplied options before spreading them into the outbound
70
+ // POST body (CWE-284/CWE-1321 — PER-8722): drop prototype-pollution keys
71
+ // and code-bearing fields the SDK must never forward. clientInfo /
72
+ // environmentInfo are hard-coded AFTER the spread so callers can't override.
73
+ const BLOCKED_OPTION_KEYS = new Set([
74
+ '__proto__', 'constructor', 'prototype', 'execute', 'domTransformation'
75
+ ]);
76
+ const safeOptions = {};
77
+ for (const key of Object.keys(snapshotOptions)) {
78
+ if (BLOCKED_OPTION_KEYS.has(key)) {
79
+ log.debug?.(`Ignoring disallowed percySnapshot option: ${key}`);
80
+ continue;
81
+ }
82
+ safeOptions[key] = snapshotOptions[key];
83
+ }
84
+
66
85
  const postData = {
67
- ...snapshotOptions,
86
+ ...safeOptions,
68
87
  domSnapshot,
69
88
  environmentInfo: ENV_INFO,
70
89
  clientInfo: CLIENT_INFO,
package/lib/snapshot.js CHANGED
@@ -127,6 +127,17 @@ function getCookies(browser) {
127
127
  }).catch(() => []);
128
128
  }
129
129
 
130
+ // Cookie names that commonly hold session/auth secrets. These are stripped from
131
+ // the snapshot payload by default so credentials aren't forwarded to the Percy
132
+ // daemon and on to the cloud (CWE-200). Set PERCY_FORWARD_ALL_COOKIES=true to
133
+ // restore forwarding the full cookie jar.
134
+ const SENSITIVE_COOKIE_PATTERN = /session|token|auth|sid|jwt|bearer|csrf|xsrf/i;
135
+
136
+ function filterSensitiveCookies(cookies) {
137
+ if (process.env.PERCY_FORWARD_ALL_COOKIES === 'true' || !Array.isArray(cookies)) return cookies;
138
+ return cookies.filter(cookie => !SENSITIVE_COOKIE_PATTERN.test(cookie?.name || ''));
139
+ }
140
+
130
141
  function resolveMaxFrameDepth(options = {}, utils) {
131
142
  return clampFrameDepth(
132
143
  options.maxIframeDepth ??
@@ -398,7 +409,7 @@ async function captureSerializedDOM(browser, options = {}, utils, domScript = nu
398
409
  }, [serializeOptions]);
399
410
 
400
411
  if (!domSnapshot) domSnapshot = {};
401
- domSnapshot.cookies = await getCookies(browser);
412
+ domSnapshot.cookies = filterSensitiveCookies(await getCookies(browser));
402
413
 
403
414
  // Capture cross-origin iframes. ctx carries the per-call domScript + log so
404
415
  // concurrent percySnapshot invocations don't race on shared module state.
@@ -726,6 +737,7 @@ module.exports = {
726
737
  slowScrollToBottom,
727
738
  ignoreCanvasSerializationErrors,
728
739
  ignoreStyleSheetSerializationErrors,
740
+ filterSensitiveCookies,
729
741
  isUnsupportedIframeSrc,
730
742
  getOrigin,
731
743
  captureCorsIframes,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@percy/nightwatch",
3
3
  "description": "Nightwatch client library for visual testing with Percy",
4
- "version": "2.2.1-beta.1",
4
+ "version": "2.2.1-beta.2",
5
5
  "license": "MIT",
6
6
  "author": "Perceptual Inc.",
7
7
  "repository": "https://github.com/percy/percy-nightwatch",