Skip to content

feat(rrweb): add opt-in selectiveMaskingAttribute for selective masking#842

Open
melodyaws wants to merge 1 commit into
aws-observability:mainfrom
melodyaws:feat/selective-masking
Open

feat(rrweb): add opt-in selectiveMaskingAttribute for selective masking#842
melodyaws wants to merge 1 commit into
aws-observability:mainfrom
melodyaws:feat/selective-masking

Conversation

@melodyaws

Copy link
Copy Markdown

Issue #, if available

N/A — opening directly per the contributing guide. Happy to convert to an issue first if maintainers prefer.

Description of changes

Adds an opt-in selectiveMaskingAttribute option to RRWebPlugin so customers can record non-sensitive UI context (button labels, headings, dashboard layout) while still masking PII fields by attribute.

The default is unchanged — when the option is omitted (or set to an empty string), the plugin continues to enforce full maskAllInputs: true / maskTextSelector: '*' masking. Customers must pass a non-empty attribute string to opt in.

new RRWebPlugin({ selectiveMaskingAttribute: 'data-rum-mask' });
<input type="email" data-rum-mask />   <!-- masked in replay -->
<button>Submit</button>                <!-- recorded as text -->

Why

Out of the box, every text node and input becomes *** in playback, which makes replay much less useful for debugging support tickets where the page context (which step of the flow the user was on, which button label was showing, which dashboard) matters more than the PII fields themselves. Today the only way to get this is to patch node_modules post-install, which is fragile and has to be reapplied on every npm install.

Privacy posture

  • Default behavior is bit-for-bit identical when the new option is unset (covered by an explicit unit test).
  • maskAllInputs / maskTextSelector / maskInputOptions / maskInputFn remain non-overridable via recordOptions — they are derived from selectiveMaskingAttribute and managed by the plugin (covered by an explicit unit test).
  • Attribute string is escaped before being interpolated into the CSS selector, so it cannot break out of […] (covered by a unit test).
  • Docs flag the privacy review requirement before enabling.

Tests

  • Default unchanged when option omitted ✅
  • Default unchanged when option is an empty string ✅
  • Switches to attribute-driven masking when set ✅
  • maskInputFn masks elements that carry the attribute, leaves others as text ✅
  • CSS-injection-style payloads escape correctly ✅
  • recordOptions.maskInputFn cannot smuggle a custom function past the plugin ✅
  • Full unit-test suite: 756 / 756 passing locally
  • npm run build succeeds for core / slim / web
  • npm run lint — 0 errors

Checklist

  • No breaking changes (default behavior preserved)
  • Unit tests added
  • Docs (docs/plugins/RRWebPlugin.md) updated
  • npm run lint — 0 errors
  • npm run build — succeeds

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Adds a new RRWebPluginConfig option, selectiveMaskingAttribute, that lets
customers mask only DOM elements carrying a specific attribute (e.g.
data-rum-mask) instead of every text node and input.

The default behavior is unchanged: when the option is omitted or empty,
the plugin continues to enforce maskAllInputs: true and
maskTextSelector: '*'. Customers opt in by passing a non-empty attribute
string.

The plugin still does not allow maskAllInputs / maskTextSelector /
maskInputOptions / maskInputFn to be supplied via recordOptions — those
values are derived from selectiveMaskingAttribute and managed by the
plugin. The attribute string is escaped before being interpolated into a
CSS selector to prevent breaking out of [...].

- Unit tests: default behavior preserved, attribute-driven masking,
  CSS selector escaping, and recordOptions cannot smuggle in maskInputFn.
- Docs: new "Opt-in: selective masking" section with example usage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

══════════════════════════════════════════════════════════════════════
  FULL BUNDLE: cwr.js
══════════════════════════════════════════════════════════════════════
  Total:  167.1 KB raw  /  50.7 KB gzip  (EXACT)
──────────────────────────────────────────────────────────────────────
  Category                              Raw % of total
──────────────────────────────────────────────────────────────────────
  rrweb                             67.3 KB      40.3%
  app: plugins                      27.4 KB      16.4%
  aws-sdk/smithy                    17.8 KB      10.7%
  web-vitals                        10.8 KB       6.5%
  app: dispatch                     10.2 KB       6.1%
  app: sessions                      7.7 KB       4.6%
  app: orchestration                 5.9 KB       3.5%
  app: event-cache                   5.4 KB       3.2%
  app: auth                          4.6 KB       2.7%
  app: utils                         2.9 KB       1.8%
  app: other                         2.4 KB       1.5%
  tslib                              1.5 KB       0.9%
  shimmer                            1.4 KB       0.8%
  uuid                               0.8 KB       0.5%
  app: event-bus                     0.4 KB       0.2%
  app: remote-config                 0.4 KB       0.2%
  webpack runtime                    0.1 KB       0.1%
  (unattributed/boilerplate)         0.1 KB       0.1%
──────────────────────────────────────────────────────────────────────
  Sizes are EXACT (from source map character attribution).
  Gzip total is EXACT. Per-category gzip is not shown (not additive).

  All modules (111):
       15.5 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb-snapshot/es/rrweb-snapshot.js
       11.2 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observer.js
       10.8 KB  ../../node_modules/web-vitals/dist/web-vitals.attribution.js
        7.7 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/mutation.js
        6.8 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/index.js
        6.8 KB  ../../node_modules/rrweb/es/rrweb/_virtual/image-bitmap-data-url-worker.js
        5.4 KB  ../core/src/event-cache/EventCache.ts
        5.3 KB  ../core/src/sessions/SessionManager.ts
        4.2 KB  ../core/src/dispatch/Dispatch.ts
        4.1 KB  ../core/src/plugins/event-plugins/NavigationPlugin.ts
        3.8 KB  ../core/src/plugins/event-plugins/XhrPlugin.ts
        3.8 KB  ../core/src/plugins/event-plugins/RRWebPlugin.ts
        3.8 KB  ../slim/src/orchestration/Orchestration.ts
        3.4 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/utils.js
        3.4 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/iframe-manager.js
        3.1 KB  ../../node_modules/@smithy/signature-v4/dist-es/SignatureV4.js
        2.9 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observers/canvas/canvas-manager.js
        2.8 KB  ../core/src/plugins/event-plugins/FetchPlugin.ts
        2.5 KB  ../core/src/plugins/event-plugins/WebVitalsPlugin.ts
        2.4 KB  ../core/src/sessions/PageManager.ts
        2.4 KB  ../core/src/dispatch/CognitoIdentityClient.ts
        2.3 KB  ../../node_modules/@smithy/signature-v4/dist-es/HeaderFormatter.js
        2.2 KB  ../../node_modules/@smithy/fetch-http-handler/dist-es/fetch-http-handler.js
        2.2 KB  ../core/src/plugins/utils/http-utils.ts
        2.0 KB  ../core/src/plugins/event-plugins/DomEventPlugin.ts
        1.8 KB  ../slim/src/CommandQueue.ts
        1.8 KB  ../../node_modules/@aws-crypto/sha256-js/build/module/RawSha256.js
        1.8 KB  ../core/src/dispatch/DataPlaneClient.ts
        1.6 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observers/canvas/serialize-args.js
        1.5 KB  ../../node_modules/tslib/tslib.es6.mjs
        1.4 KB  ../../node_modules/shimmer/index.js
        1.3 KB  ./src/orchestration/Orchestration.ts
        1.3 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/shadow-dom-manager.js
        1.2 KB  ../core/src/plugins/event-plugins/ResourcePlugin.ts
        1.2 KB  ../core/src/utils/common-utils.ts
        1.2 KB  ../../node_modules/@smithy/signature-v4/dist-es/SignatureV4Base.js
        1.2 KB  ../../node_modules/rrweb/es/rrweb/packages/types/dist/types.js
        1.0 KB  ../core/src/dispatch/FetchHttpHandler.ts
        1.0 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/cross-origin-iframe-mirror.js
        1.0 KB  ../core/src/dispatch/Authentication.ts
        1.0 KB  ../core/src/plugins/event-plugins/JsErrorPlugin.ts
        0.9 KB  ../core/src/plugins/event-plugins/PageViewPlugin.ts
        0.9 KB  ../core/src/utils/InternalLogger.ts
        0.9 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/stylesheet-manager.js
        0.9 KB  ../core/src/dispatch/StsClient.ts
        0.9 KB  ../core/src/plugins/PluginManager.ts
        0.9 KB  ../../node_modules/@aws-crypto/sha256-js/build/module/jsSha256.js
        0.9 KB  ../../node_modules/@smithy/protocol-http/dist-es/httpRequest.js
        0.8 KB  ../../node_modules/@aws-crypto/sha256-js/build/module/constants.js
        0.8 KB  ../core/src/plugins/utils/js-error-utils.ts
        0.8 KB  ../core/src/dispatch/BasicAuthentication.ts
        0.7 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observers/canvas/webgl.js
        0.7 KB  ../core/src/dispatch/compression.ts
        0.6 KB  ../../node_modules/rrweb/es/rrweb/ext/tslib/tslib.es6.js
        0.6 KB  ../../node_modules/@smithy/signature-v4/dist-es/constants.js
        0.6 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observers/canvas/2d.js
        0.6 KB  ../core/src/utils/cookies-utils.ts
        0.5 KB  ../core/src/dispatch/EnhancedAuthentication.ts
        0.5 KB  ../../node_modules/@smithy/util-hex-encoding/dist-es/index.js
        0.5 KB  ../core/src/dispatch/RetryHttpHandler.ts
        0.5 KB  ../../node_modules/rrweb/es/rrweb/_virtual/_rollup-plugin-web-worker-loader__helper__browser__createBase64WorkerFactory.js
        0.4 KB  ../core/src/orchestration/config.ts
        0.4 KB  ../../node_modules/rrweb/es/rrweb/ext/base64-arraybuffer/dist/base64-arraybuffer.es5.js
        0.4 KB  ../core/src/plugins/utils/constant.ts
        0.4 KB  ../core/src/event-bus/EventBus.ts
        0.4 KB  ../core/src/plugins/MonkeyPatched.ts
        0.4 KB  ../../node_modules/@smithy/signature-v4/dist-es/credentialDerivation.js
        0.4 KB  ./src/remote-config/remote-config.ts
        0.3 KB  ../core/src/dispatch/BeaconHttpHandler.ts
        0.3 KB  ./src/orchestration/config.ts
        0.3 KB  ../../node_modules/rrweb/es/rrweb/packages/rrweb/src/record/observers/canvas/canvas.js
        0.3 KB  ../../node_modules/@smithy/signature-v4/dist-es/getCanonicalQuery.js
        0.3 KB  ../core/src/dispatch/signing.ts
        0.3 KB  ../../node_modules/@smithy/signature-v4/dist-es/getPayloadHash.js
        0.3 KB  ../../node_modules/uuid/dist/esm-browser/rng.js
        0.3 KB  ./src/CommandQueue.ts
        0.3 KB  ../../node_modules/@aws-crypto/util/build/module/convertToBuffer.js
        0.3 KB  ../../node_modules/uuid/dist/esm-browser/stringify.js
        0.3 KB  ../../node_modules/rrweb/es/rrweb/_virtual/_rollup-plugin-web-worker-loader__helper__node__createBase64WorkerFactory.js
        0.3 KB  ../core/src/plugins/utils/performance-utils.ts
        0.3 KB  ../../node_modules/@smithy/protocol-http/dist-es/httpResponse.js
        0.3 KB  ../core/src/plugins/InternalPlugin.ts
        0.2 KB  ../../node_modules/rrweb/es/rrweb/_virtual/_rollup-plugin-web-worker-loader__helper__node__WorkerClass.js
        0.2 KB  ../../node_modules/@smithy/signature-v4/dist-es/moveHeadersToQuery.js
        0.2 KB  ../../node_modules/@smithy/querystring-builder/dist-es/index.js
        0.2 KB  ../../node_modules/@smithy/signature-v4/dist-es/getCanonicalHeaders.js
        0.2 KB  ./src/index-browser.ts
        0.2 KB  ../core/src/dispatch/utils.ts
        0.2 KB  ../../node_modules/uuid/dist/esm-browser/v4.js
        0.2 KB  ../core/node_modules/@smithy/util-hex-encoding/dist-es/index.js
        0.2 KB  ../../node_modules/@smithy/signature-v4/dist-es/utilDate.js
        0.2 KB  ../../node_modules/@smithy/fetch-http-handler/dist-es/request-timeout.js
        0.1 KB  ../../node_modules/@smithy/util-utf8/dist-es/toUint8Array.js
        0.1 KB  ../core/src/dispatch/request-timeout.ts
        0.1 KB  ../core/src/utils/random.ts
        0.1 KB  webpack/bootstrap
        0.1 KB  ../../node_modules/@smithy/is-array-buffer/dist-es/index.js
        0.1 KB  ../../node_modules/@smithy/signature-v4/dist-es/prepareRequest.js
        0.1 KB  ../../node_modules/@smithy/util-uri-escape/dist-es/escape-uri.js
        0.1 KB  ../../node_modules/@smithy/signature-v4/dist-es/headerUtil.js
        0.1 KB  ../../node_modules/rrweb/es/rrweb/_virtual/_rollup-plugin-web-worker-loader__helper__auto__isNodeJS.js
        0.1 KB  ../../node_modules/uuid/dist/esm-browser/native.js
        0.1 KB  ../core/src/errors/XhrError.ts
        0.1 KB  ../../node_modules/@smithy/util-middleware/dist-es/normalizeProvider.js
        0.1 KB  ../core/src/utils/constants.ts
        0.1 KB  ../../node_modules/@aws-crypto/util/build/module/isEmptyData.js
        0.0 KB  ../../node_modules/rrweb/es/rrweb/_virtual/_rollup-plugin-web-worker-loader__helper__auto__createBase64WorkerFactory.js
        0.0 KB  ../../node_modules/@smithy/fetch-http-handler/dist-es/create-request.js
        0.0 KB  ../../node_modules/@smithy/util-utf8/dist-es/fromUtf8.browser.js
        0.0 KB  ../../node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/dist-es/fromUtf8.browser.js
        0.0 KB  ../core/src/utils/version.ts


══════════════════════════════════════════════════════════════════════
  SLIM BUNDLE: cwr-slim.js
══════════════════════════════════════════════════════════════════════
  Total:  36.5 KB raw  /  10.7 KB gzip  (EXACT)
──────────────────────────────────────────────────────────────────────
  Category                              Raw % of total
──────────────────────────────────────────────────────────────────────
  app: dispatch                      8.7 KB      23.8%
  app: sessions                      7.7 KB      21.1%
  app: event-cache                   5.4 KB      14.7%
  app: orchestration                 4.2 KB      11.5%
  app: plugins                       2.7 KB       7.3%
  app: other                         2.1 KB       5.7%
  app: utils                         1.6 KB       4.3%
  aws-sdk/smithy                     1.4 KB       4.0%
  shimmer                            1.4 KB       3.8%
  uuid                               0.8 KB       2.3%
  app: event-bus                     0.4 KB       1.1%
  webpack runtime                    0.1 KB       0.3%
──────────────────────────────────────────────────────────────────────
  Sizes are EXACT (from source map character attribution).
  Gzip total is EXACT. Per-category gzip is not shown (not additive).

  All modules (35):
        5.4 KB  web-slim/../core/src/event-cache/EventCache.ts
        5.3 KB  web-slim/../core/src/sessions/SessionManager.ts
        4.2 KB  web-slim/../core/src/dispatch/Dispatch.ts
        3.8 KB  web-slim/./src/orchestration/Orchestration.ts
        2.4 KB  web-slim/../core/src/sessions/PageManager.ts
        1.8 KB  web-slim/./src/CommandQueue.ts
        1.8 KB  web-slim/../core/src/dispatch/DataPlaneClient.ts
        1.4 KB  web-slim/../../node_modules/shimmer/index.js
        1.0 KB  web-slim/../core/src/dispatch/FetchHttpHandler.ts
        0.9 KB  web-slim/../core/src/plugins/event-plugins/PageViewPlugin.ts
        0.9 KB  web-slim/../core/src/utils/InternalLogger.ts
        0.9 KB  web-slim/../core/src/plugins/PluginManager.ts
        0.9 KB  web-slim/../../node_modules/@smithy/protocol-http/dist-es/httpRequest.js
        0.7 KB  web-slim/../core/src/dispatch/compression.ts
        0.6 KB  web-slim/../core/src/utils/cookies-utils.ts
        0.5 KB  web-slim/../core/src/dispatch/RetryHttpHandler.ts
        0.4 KB  web-slim/../core/src/orchestration/config.ts
        0.4 KB  web-slim/../core/src/event-bus/EventBus.ts
        0.4 KB  web-slim/../core/src/plugins/MonkeyPatched.ts
        0.3 KB  web-slim/../core/src/dispatch/BeaconHttpHandler.ts
        0.3 KB  web-slim/../../node_modules/uuid/dist/esm-browser/rng.js
        0.3 KB  web-slim/../../node_modules/uuid/dist/esm-browser/stringify.js
        0.3 KB  web-slim/../../node_modules/@smithy/protocol-http/dist-es/httpResponse.js
        0.2 KB  web-slim/../core/src/plugins/InternalPlugin.ts
        0.2 KB  web-slim/../../node_modules/@smithy/querystring-builder/dist-es/index.js
        0.2 KB  web-slim/./src/index-browser.ts
        0.2 KB  web-slim/../../node_modules/uuid/dist/esm-browser/v4.js
        0.1 KB  web-slim/../core/src/dispatch/request-timeout.ts
        0.1 KB  web-slim/../core/src/plugins/utils/http-utils.ts
        0.1 KB  web-slim/webpack/bootstrap
        0.1 KB  web-slim/../../node_modules/@smithy/util-uri-escape/dist-es/escape-uri.js
        0.1 KB  web-slim/../core/src/plugins/utils/constant.ts
        0.1 KB  web-slim/../../node_modules/uuid/dist/esm-browser/native.js
        0.1 KB  web-slim/../core/src/utils/constants.ts
        0.0 KB  web-slim/../core/src/utils/version.ts

  Slim saves 79% gzip vs full (EXACT).

Report written to reports/bundle-stats-both.txt

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.

1 participant