Skip to content

fix(plugin-autocapture-browser): do not capture element text for 'contenteditable' - #2066

Open
daniel-graham-amplitude wants to merge 1 commit into
mainfrom
SDK-402-content-editable-redact
Open

daniel-graham-amplitude wants to merge 1 commit into
mainfrom
SDK-402-content-editable-redact

Conversation

@daniel-graham-amplitude

@daniel-graham-amplitude daniel-graham-amplitude commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

PROBLEM:
When an element has the contenteditable attribute it means that the element is "editable by the user". This means that the inner text of a "contenteditable element" is semantically equivalent to the "value" attribute on an input element; and it should be excluded from autocapture.

SOLUTION:
Do not capture Element Text on elements that have the "contenteditable" attribute.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?:

Note

Low Risk
Privacy-focused autocapture change that reduces PII leakage from rich text editors; behavior may differ for apps that relied on Element Text inside contenteditable regions.

Overview
Stops autocapture from sending Element Text for user-editable DOM, treating contenteditable like sensitive form fields.

Adds isContentEditableElement, which walks ancestors for the nearest contenteditable attribute (any value except "false", including plaintext-only and empty). getText returns empty for editable elements so [Amplitude] Element Text is dropped from event properties; descendants inside an editing host are omitted unless a closer contenteditable="false" island restores static text. isNonSensitiveElement now uses the same helper instead of only checking contenteditable="true" on the element itself.

Tests and the autocapture test-server page document inherited editability and nested contenteditable="false" boundaries.

Reviewed by Cursor Bugbot for commit b3e27af. Bugbot is set up for automated code reviews on this repo. Configure here.

@linear-code

linear-code Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

SDK-402

@daniel-graham-amplitude
daniel-graham-amplitude requested review from Mercy811 and removed request for Dogfalo October 16, 2026 22:26
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

size-limit report 📦

Path Size
packages/analytics-browser/lib/scripts/amplitude-min.js.gz 67.5 KB (+0.04% 🔺)
packages/session-replay-browser/lib/scripts/session-replay-browser-min.js.gz 136.37 KB (0%)
packages/unified/lib/scripts/amplitude-min.umd.js.gz 221.59 KB (+0.02% 🔺)
@amplitude/element-selector (gzipped esm) 3.48 KB (0%)

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/plugin-autocapture-browser/src/helpers.ts
@daniel-graham-amplitude
daniel-graham-amplitude force-pushed the SDK-402-content-editable-redact branch from 542b379 to cb954f7 Compare October 19, 2026 17:26
@daniel-graham-amplitude

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T23:23:25.886686Z b3e27af Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb954f7684

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


getText = (element: Element): string => {
// Editable regions hold user-entered text. Omit it so Element Text is dropped.
if (isContentEditableElement(element)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Check effective editability through ancestors

When the tracked element is a descendant of a contenteditable region, this check returns false because the descendant usually has no attribute of its own, even though editability is inherited. For example, a click on a nested button, a custom-allowlisted span, or an action-click descendant inside contenteditable="plaintext-only" causes getText to read and transmit that descendant's user-entered text. Determine effective editability (respecting the nearest contenteditable="false" boundary) rather than checking only the element itself.

Useful? React with 👍 / 👎.

@daniel-graham-amplitude
daniel-graham-amplitude force-pushed the SDK-402-content-editable-redact branch from cb954f7 to b3e27af Compare October 20, 2026 23:18
@daniel-graham-amplitude
daniel-graham-amplitude requested a review from a team as a code owner October 20, 2026 23:18
@daniel-graham-amplitude

Copy link
Copy Markdown
Collaborator Author

@codex review

@daniel-graham-amplitude

Copy link
Copy Markdown
Collaborator Author

bugbot run

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b3e27af68b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (current instanceof HTMLElement) {
const value = current.getAttribute('contenteditable');
if (value !== null) {
return value.toLowerCase() !== 'false';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Continue past invalid contenteditable values

When markup uses an invalid enumerated value such as contenteditable="inherit", the HTML standard defines it as inherited, but this branch treats every value except false as editable. On a standalone element or below contenteditable="false", getText now returns empty and hierarchy attribute capture is suppressed even though the browser considers the element noneditable, silently dropping ordinary analytics data. Recognize only the empty, true, and plaintext-only states as editable and continue walking for invalid values.

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b3e27af. Configure here.

element instanceof HTMLElement ? element.getAttribute('contenteditable')?.toLowerCase() === 'true' : false;

return !SENSITIVE_TAGS.includes(tag) && !isContentEditable;
return !SENSITIVE_TAGS.includes(tag) && !isContentEditableElement(element);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Editable descendants lose hierarchy attributes

Medium Severity

isNonSensitiveElement now calls isContentEditableElement, so any node inside an editing host is treated as sensitive. Hierarchy collection then drops attributes such as aria-label and data-amp-track-* on nested buttons, links, and chips. The change is scoped to omitting Element Text, so those identifying properties disappear on clicks inside editors.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b3e27af. Configure here.

This branch has not been deployed

No deployments
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.

2 participants