Skip to content

Commit c0eb753

Browse files
chargomeclaude
andauthored
fix(v10/core): Apply dataCollection.urlQueryParams to collected URLs and query strings (#24572)
Backport of: #23060, #23061, #23143, and the URL-query part of #22853 `dataCollection.urlQueryParams` shipped on v10, but it was never wired to the URL fields, so `request.url`, `request.query_string`, `url.full`, `url.query` and their legacy aliases were sent unfiltered. The wiring only landed on `develop`, after the v10 branch was cut. ## Differences to the original PRs - #22853: only the `requestdata.ts` query-string filtering and the `filterQueryParams` rewrite it depends on are included. The v11 default changes, the `include` resolution rewrite, event cookie/header filtering, the browser `httpclient` changes and the MIGRATION notes are left out, as they are breaking or out of scope. - v10 attribute names are kept. Where develop writes `url.full` / `url.query`, v10 still writes `http.url`, `http.query`, `http.target` and `url`; these are now filtered instead of renamed. Tests assert on the v10 names. - `filterCollectedUrlQuery` preserves a leading `?`, because v10 records `URL.search` verbatim in `http.query` / `url.query`. - Legacy duplicates outside the original diff are filtered too (`http.url` in the core and node-core http server spans, core fetch, browser fetch/XHR). - `google-cloud-http`: only the span-name query stripping is kept; v10 never set `url.full` there. - `nitro`: unchanged, since `getHttpSpanDetailsFromUrlObject` already falls back to `getClient()`. - The undici breadcrumb test lives in `node-core`, where that code sits on v10. - Extra commit for sites that no longer exist on develop: Next.js pages/edge `wrapApiHandlerWithSentry`, Remix `http.url` (tracing channel and vendored instrumentation), and Ember `url.full`. --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent d525a2f commit c0eb753

59 files changed

Lines changed: 951 additions & 177 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.size-limit.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ module.exports = [
480480
ignore: [...builtinModules, ...nodePrefixedBuiltinModules],
481481
gzip: false,
482482
brotli: false,
483-
limit: '490 KiB',
483+
limit: '492 KiB',
484484
disablePlugins: ['@size-limit/webpack'],
485485
webpack: false,
486486
modifyEsbuildConfig: function (config) {

‎dev-packages/node-integration-tests/suites/express/tracing/withError/test.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,21 @@ describe('express tracing with error', () => {
2626
runner.makeRequest('get', '/test/123/abc?q=1');
2727
await runner.completed();
2828
});
29+
30+
test('preserves encoded query parameters while filtering sensitive values on events', async () => {
31+
const runner = createRunner()
32+
.ignore('transaction')
33+
.expect({
34+
event: {
35+
request: {
36+
query_string: 'q=hello%20world&token=[Filtered]',
37+
},
38+
},
39+
})
40+
.start();
41+
42+
await runner.makeRequest('get', '/test/123/abc?q=hello%20world&token=secret');
43+
await runner.completed();
44+
});
2945
});
3046
});

‎packages/angular/src/tracing.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ import {
2222
getAbsoluteUrl,
2323
} from '@sentry/browser';
2424
import type { Integration, Span } from '@sentry/core';
25-
import { debug, parseStringToURLObject, stripUrlQueryAndFragment, timestampInSeconds } from '@sentry/core';
25+
import {
26+
debug,
27+
parseStringToURLObject,
28+
stripUrlQueryAndFragment,
29+
timestampInSeconds,
30+
filterCollectedUrl,
31+
} from '@sentry/core';
2632
import type { Observable } from 'rxjs';
2733
import { Subscription } from 'rxjs';
2834
import { filter, tap } from 'rxjs/operators';
@@ -71,7 +77,7 @@ export function _updateSpanAttributesForParametrizedUrl(route: string, url: stri
7177
span.setAttributes({
7278
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.${op}.angular`,
7379
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
74-
[URL_FULL]: absoluteUrl,
80+
[URL_FULL]: filterCollectedUrl(absoluteUrl),
7581
[URL_PATH]: parseStringToURLObject(absoluteUrl)?.pathname,
7682
[URL_TEMPLATE]: route,
7783
});

‎packages/astro/src/server/middleware.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
spanToJSON,
1212
stripUrlQueryAndFragment,
1313
winterCGRequestToRequestData,
14+
filterCollectedUrl,
15+
filterCollectedUrlQuery,
1416
} from '@sentry/core';
1517
import {
1618
captureException,
@@ -219,7 +221,7 @@ async function instrumentRequestStartHttpServerSpan(
219221
[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method,
220222
// This is here for backwards compatibility, we used to set this here before
221223
method,
222-
[URL_FULL]: ctx.url.href,
224+
[URL_FULL]: filterCollectedUrl(ctx.url.href),
223225
[URL_PATH]: ctx.url.pathname,
224226
url: stripUrlQueryAndFragment(ctx.url.href),
225227
...httpHeadersToSpanAttributes(
@@ -233,7 +235,7 @@ async function instrumentRequestStartHttpServerSpan(
233235
}
234236

235237
if (ctx.url.search) {
236-
attributes['http.query'] = ctx.url.search;
238+
attributes['http.query'] = filterCollectedUrlQuery(ctx.url.search);
237239
}
238240

239241
if (ctx.url.hash) {

‎packages/aws-serverless/src/requestSpanOptions.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919
import { CLOUD_ACCOUNT_ID, FAAS_COLDSTART, URL_FULL } from '@sentry/conventions/attributes';
2020
import type { SpanAttributes, StartSpanOptions } from '@sentry/core';
21-
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_KIND } from '@sentry/core';
21+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_KIND, filterCollectedUrl } from '@sentry/core';
2222
import type { Context } from 'aws-lambda';
2323
import { ATTR_FAAS_EXECUTION, ATTR_FAAS_ID } from './semconv';
2424

@@ -62,7 +62,7 @@ function extractOtherEventFields(event: unknown): SpanAttributes {
6262
const answer: SpanAttributes = {};
6363
const fullUrl = extractFullUrl(event as ApiGatewayLikeEvent);
6464
if (fullUrl) {
65-
answer[URL_FULL] = fullUrl;
65+
answer[URL_FULL] = filterCollectedUrl(fullUrl);
6666
}
6767
return answer;
6868
}

‎packages/browser-utils/src/metrics/browserMetrics.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
setMeasurement,
1212
spanToJSON,
1313
stringMatchesSomePattern,
14+
filterCollectedUrl,
1415
} from '@sentry/core';
1516
import { htmlTreeAsString } from '../htmlTreeAsString';
1617
import { WINDOW } from '../types';
@@ -775,7 +776,7 @@ export function _addResourceSpans(
775776

776777
attributes['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);
777778

778-
attributes[URL_FULL] = resourceUrl;
779+
attributes[URL_FULL] = filterCollectedUrl(resourceUrl);
779780

780781
_setResourceRequestAttributes(entry, attributes, [
781782
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStatus

‎packages/browser/src/integrations/fetchStreamPerformance.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
1010
startInactiveSpan,
1111
stripDataUrlContent,
12+
filterCollectedUrl,
1213
} from '@sentry/core';
1314

1415
const responseToStreamSpan = new WeakMap<object, Span>();
@@ -80,7 +81,7 @@ export const fetchStreamPerformanceIntegration = defineIntegration(() => {
8081
name: `${method} ${sanitizedUrl}`,
8182
startTime: handlerData.endTimestamp,
8283
attributes: {
83-
url: stripDataUrlContent(url),
84+
url: filterCollectedUrl(stripDataUrlContent(url)),
8485
'http.method': method,
8586
type: 'fetch',
8687
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client.stream',

‎packages/browser/src/integrations/httpcontext.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineIntegration, safeSetSpanJSONAttributes } from '@sentry/core/browser';
1+
import { defineIntegration, filterCollectedUrl, safeSetSpanJSONAttributes } from '@sentry/core/browser';
22
import { getHttpRequestData, WINDOW } from '../helpers';
33
import { HTTP_REQUEST_HEADER_KEY_BASE, SENTRY_OP, URL_FULL, USER_AGENT_ORIGINAL } from '@sentry/conventions/attributes';
44

@@ -45,7 +45,7 @@ export const httpContextIntegration = defineIntegration(() => {
4545
...(span.is_segment && {
4646
// Coerce empty string to undefined so the helper's nullish check drops it,
4747
// rather than writing an empty `url.full` attribute onto the span.
48-
[URL_FULL]: span.attributes?.[SENTRY_OP] !== 'http.client' ? reqData.url : undefined,
48+
[URL_FULL]: span.attributes?.[SENTRY_OP] !== 'http.client' ? filterCollectedUrl(reqData.url) : undefined,
4949
[`${HTTP_REQUEST_HEADER_KEY_BASE}.referer`]: reqData.headers['Referer'],
5050
}),
5151
});

‎packages/browser/src/tracing/browserTracingIntegration.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
startTrackingLongTasks,
4646
} from '@sentry/browser-utils';
4747
import { DEBUG_BUILD } from '../debug-build';
48+
import { filterCollectedUrl } from '@sentry/core';
4849
import { getHttpRequestData, WINDOW } from '../helpers';
4950
import { fetchStreamPerformanceIntegration } from '../integrations/fetchStreamPerformance';
5051
import { WEB_VITALS_INTEGRATION_NAME, webVitalsIntegration } from '../integrations/webVitals';
@@ -431,7 +432,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption
431432

432433
const attributes = {
433434
...(urlObject?.pathname && { [URL_PATH]: urlObject.pathname }),
434-
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: urlObject.href }),
435+
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: filterCollectedUrl(urlObject.href) }),
435436
...finalStartSpanOptions.attributes,
436437
};
437438

‎packages/browser/src/tracing/request.ts‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import type {
1010
} from '@sentry/core/browser';
1111
import {
1212
addFetchInstrumentationHandler,
13+
filterCollectedUrl,
14+
filterCollectedUrlQuery,
1315
getActiveSpan,
1416
getClient,
1517
getLocationHref,
@@ -174,10 +176,10 @@ export function instrumentOutgoingRequests(client: Client, _options?: Partial<Re
174176
const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;
175177
createdSpan.setAttributes({
176178
// oxlint-disable-next-line typescript/no-deprecated
177-
[HTTP_URL]: sanitizedFullUrl,
179+
[HTTP_URL]: filterCollectedUrl(sanitizedFullUrl),
178180
// `url.full` must match `http.url`. Setting it here ensures parentless `http.client`
179181
// segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).
180-
[URL_FULL]: sanitizedFullUrl,
182+
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
181183
'server.address': host,
182184
});
183185

@@ -389,17 +391,17 @@ function xhrCallback(
389391
? startInactiveSpan({
390392
name: `${method} ${urlForSpanName}`,
391393
attributes: {
392-
url: stripDataUrlContent(url),
394+
url: filterCollectedUrl(stripDataUrlContent(url)),
393395
type: 'xhr',
394396
'http.method': method,
395-
'http.url': sanitizedFullUrl,
397+
'http.url': filterCollectedUrl(sanitizedFullUrl),
396398
// `url.full` must match `http.url`. Setting it here ensures parentless `http.client`
397399
// segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).
398-
[URL_FULL]: sanitizedFullUrl,
400+
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
399401
'server.address': parsedUrl?.host,
400402
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
401403
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',
402-
...(parsedUrl?.search && { 'http.query': parsedUrl?.search }),
404+
...(parsedUrl?.search && { 'http.query': filterCollectedUrlQuery(parsedUrl?.search) }),
403405
...(parsedUrl?.hash && { 'http.fragment': parsedUrl?.hash }),
404406
},
405407
})

0 commit comments

Comments
 (0)