Skip to content

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

Open
s1gr1d wants to merge 9 commits into
developfrom
sig/http-body-filtering
Open

s1gr1d wants to merge 9 commits 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 passes through unchanged: the SDK
only scrubs values it can attribute to a specific sensitive key, since Relay scrubs
server-side anyway and cannot tell an SDK-filtered value from a literal one. 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.

Relay scrubs as well, see this related PR: getsentry/sentry-conventions#625

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 unchanged, scrubbed server-side by Relay not captured
20 KB JSON, fully received filtered JSON, then truncated ({"note":"xxx...) not captured
body cut off mid-stream by the size cap captured prefix, truncated — unparseable, so left to Relay not captured
empty body nothing attached not captured

"Not captured" means no attribute at all.

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
Comment thread packages/core/src/utils/data-collection/filterHttpBody.ts Fixed
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.24 kB - -
@sentry/browser - with treeshaking flags 27.5 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.4 kB - -
@sentry/browser (incl. Tracing) 51.15 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 51.17 kB - -
@sentry/browser (incl. Tracing, Profiling) 54.18 kB - -
@sentry/browser (incl. Tracing, Replay) 90.76 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.86 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 95.46 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 108.41 kB - -
@sentry/browser (incl. Feedback) 46.76 kB - -
@sentry/browser (incl. sendFeedback) 34.3 kB - -
@sentry/browser (incl. FeedbackAsync) 39.41 kB - -
@sentry/browser (incl. Metrics) 30.25 kB - -
@sentry/browser (incl. Logs) 30.51 kB - -
@sentry/browser (incl. Metrics & Logs) 31.18 kB - -
@sentry/react 31 kB - -
@sentry/react (incl. Tracing) 53.45 kB - -
@sentry/vue 36.74 kB - -
@sentry/vue (incl. Tracing) 53.7 kB - -
@sentry/svelte 29.26 kB - -
CDN Bundle 30.93 kB - -
CDN Bundle (incl. Tracing) 51.69 kB - -
CDN Bundle (incl. Logs, Metrics) 33.2 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.66 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.92 kB - -
CDN Bundle (incl. Tracing, Replay) 89.28 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 91.25 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 95.45 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 97.42 kB - -
CDN Bundle - uncompressed 91.4 kB - -
CDN Bundle (incl. Tracing) - uncompressed 153.77 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.97 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 159.73 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 227.54 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 273.5 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 279.44 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 287.2 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 293.13 kB - -
@sentry/nextjs (client) 55.77 kB - -
@sentry/sveltekit (client) 51.59 kB - -
@sentry/core/server 40.12 kB +0.45% +179 B 🔺
@sentry/core/browser 13.63 kB - -
@sentry/node 134.06 kB +0.15% +189 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.4 kB - -
@sentry/node - without tracing 90.56 kB +0.16% +141 B 🔺
@sentry/node - without channel injection 112.58 kB +0.16% +179 B 🔺
@sentry/aws-serverless 98.88 kB +0.2% +188 B 🔺
@sentry/cloudflare (withSentry) - minified 206.96 kB +0.23% +472 B 🔺
@sentry/cloudflare (withSentry) 514.88 kB +0.23% +1.15 kB 🔺

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.

Stale Bugbot comment from a previous run.

Comment thread packages/core/src/utils/data-collection/filterHttpBody.ts Outdated
s1gr1d and others added 2 commits September 23, 2026 15:26
Resolved conflicts in packages/core/src/utils/request.ts (kept develop's
shouldFilterDataKey-based header filtering alongside the new body filter
imports; filterKeyValueData import dropped as unused) and in the express
tracing integration test (kept develop's span-streaming assertions with
this branch's '[Filtered]' body expectations).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/core/src/utils/data-collection/filterHttpBody.ts Fixed
@s1gr1d

s1gr1d commented Sep 24, 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 e93cb39. Configure here.

Comment thread packages/core/src/utils/data-collection/filterHttpBody.ts Outdated
@s1gr1d
s1gr1d marked this pull request as ready for review September 24, 2026 12:51
@s1gr1d
s1gr1d requested a review from JPeer264 September 24, 2026 12:51
Comment on lines +15 to +17
function isFormBody(body: string): boolean {
return body.includes('=') && body.split('&').every(segment => FORM_SEGMENT_RE.test(segment));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The isFormBody() function misidentifies XML with attributes as form-encoded, causing filterQueryParams() to corrupt the XML body when sensitive attribute names are present.
Severity: HIGH

Suggested Fix

Before applying form-body filtering, check the request's Content-Type header to ensure it is actually application/x-www-form-urlencoded. Alternatively, make the regex in isFormBody() stricter to avoid matching XML structures.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/core/src/utils/data-collection/filterHttpBody.ts#L15-L17

Potential issue: The `isFormBody()` function incorrectly classifies XML bodies
containing attributes as form-encoded because it only checks for the presence of an `=`
character. This causes the XML string to be passed to `filterQueryParams()`. For an XML
body like `<config auth_token="secret">`, the function incorrectly identifies `<config
auth_token` as a parameter key. Since this "key" contains a sensitive substring
(`auth`), the entire body is incorrectly filtered and corrupted, resulting in `<config
auth_token=[Filtered]>`. This affects any XML request body with attributes whose names
contain sensitive keywords, leading to corrupted diagnostic data.

Did we get this right? 👍 / 👎 to inform future reviews.

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