Skip to content

fix(core): Filter collected HTTP bodies and redact browser GraphQL document literals - #24178

Draft
s1gr1d wants to merge 1 commit into
developfrom
sig/http-body-filtering
Draft

fix(core): Filter collected HTTP bodies and redact browser GraphQL document literals#24178
s1gr1d wants to merge 1 commit into
developfrom
sig/http-body-filtering

Conversation

@s1gr1d

@s1gr1d s1gr1d commented Sep 7, 2026

Copy link
Copy Markdown
Member

Automatically captured HTTP request bodies went out raw, and the browser graphqlClient
attached GraphQL documents with inline literals intact.

Bodies now run through a filter at capture time, before truncation, since a truncated JSON
body no longer parses. JSON and form bodies keep their shape, and values of sensitive keys
become [Filtered]. A body without key-value structure is filtered wholesale, as the data
collection spec requires. The browser GraphQL document gets the same literal redaction the
server-side integration applies to the parsed AST.

The model follows OTel's sanitization of db.query.text: keep the structure, replace the values, never send what the SDK cannot scrub.

Request bodies (event.request.data / http.request.body.data)

Input httpBodies default (on) httpBodies: [] (off)
{"colour":"blue","password":"hunter2"} {"colour":"blue","password":"[Filtered]"} not captured
colour=blue&access_token=abc123 colour=blue&access_token=[Filtered] not captured
plain text, XML, or any non-key-value body [Filtered] not captured
20 KB JSON, fully received filtered JSON, then truncated ({"note":"xxx...) not captured
body cut off mid-stream by the size cap [Filtered] not captured
empty body nothing attached not captured

"Not captured" means no attribute at all, while [Filtered] still records that a body existed.

GraphQL document (graphql.document on span and breadcrumb)

Input graphQL.document default (on) document: false (off)
query { user(email: "jane@example.com", age: 42) { name } } query { user(email: "*", age: *) { name } } not attached
query GetUser($id: ID!) { user(id: $id) { name } } unchanged, variables are not in the document not attached

Part of #24081

@s1gr1d
s1gr1d requested review from a team as code owners September 7, 2026 13:11
@s1gr1d
s1gr1d requested review from isaacs, logaretm and mydea and removed request for a team September 7, 2026 13:11
'user-agent': expect.stringContaining(''),
'content-type': 'text/plain',
},
data: 'some plain text',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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


const result: Record<string, unknown> = {};
for (const [key, nested] of Object.entries(value)) {
result[key] = shouldFilterDataKey(key, true) ? FILTERED_VALUE : filterBodyValue(nested);
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.8 kB - -
@sentry/browser - with treeshaking flags 27.11 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27 kB - -
@sentry/browser (incl. Tracing) 49.22 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 49.22 kB - -
@sentry/browser (incl. Tracing, Profiling) 52.12 kB - -
@sentry/browser (incl. Tracing, Replay) 88.76 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.95 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 93.44 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 106.37 kB - -
@sentry/browser (incl. Feedback) 46.3 kB - -
@sentry/browser (incl. sendFeedback) 33.86 kB - -
@sentry/browser (incl. FeedbackAsync) 38.97 kB - -
@sentry/browser (incl. Metrics) 29.82 kB - -
@sentry/browser (incl. Logs) 30.09 kB - -
@sentry/browser (incl. Metrics & Logs) 30.75 kB - -
@sentry/react 30.55 kB - -
@sentry/react (incl. Tracing) 51.56 kB - -
@sentry/vue 36.05 kB - -
@sentry/vue (incl. Tracing) 51.48 kB - -
@sentry/svelte 28.83 kB - -
CDN Bundle 30.55 kB - -
CDN Bundle (incl. Tracing) 49.74 kB - -
CDN Bundle (incl. Logs, Metrics) 32.82 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 51.7 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.48 kB - -
CDN Bundle (incl. Tracing, Replay) 87.29 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 89.18 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 93.22 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 95.21 kB - -
CDN Bundle - uncompressed 90.46 kB - -
CDN Bundle (incl. Tracing) - uncompressed 148.17 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.03 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 154.14 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.29 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 267.76 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 273.71 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 281.46 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 287.4 kB - -
@sentry/nextjs (client) 54.03 kB - -
@sentry/sveltekit (client) 49.65 kB - -
@sentry/core/server 37.16 kB +0.48% +174 B 🔺
@sentry/core/browser 13.55 kB - -
@sentry/node 127.82 kB +0.17% +215 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.58 kB - -
@sentry/node - without tracing 88.85 kB +0.18% +158 B 🔺
@sentry/node - without channel injection 107.07 kB +0.18% +188 B 🔺
@sentry/aws-serverless 97.3 kB +0.24% +232 B 🔺
@sentry/cloudflare (withSentry) - minified 202.36 kB +0.21% +411 B 🔺
@sentry/cloudflare (withSentry) 503.66 kB +0.2% +997 B 🔺

View base workflow run

@s1gr1d
s1gr1d marked this pull request as draft September 7, 2026 13:43
@s1gr1d

s1gr1d commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@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, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c943d35. Configure here.

}

// The query-param filter keeps the body's original encoding byte-for-byte.
return (FORM_BODY_RE.test(body) && filterQueryParams(body, true)) || FILTERED_VALUE;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Form heuristic leaks unstructured bodies

Medium Severity

After JSON.parse fails to yield an object or array, any string matching FORM_BODY_RE is treated as form data and returned with keys intact. Unstructured bodies that merely contain = (base64 padding, JSON string scalars, prose) therefore keep their payload, and because the denylist only replaces values the bulk of that data is preserved as the key.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit c943d35. Configure here.

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