Skip to content

Commit 7e0a52f

Browse files
chargomeclaude
andauthored
fix(core): Apply dataCollection.urlQueryParams to url.full and url.query (#23061)
`urlQueryParams` only applied to `request.query_string` and `requestDataIntegration`. Everywhere else, query strings went to Sentry unfiltered — a `?token=…` was sent as-is. We filter spans in one central place (`captureSpan`) instead of at the \~57 write sites, which span \~18 packages and mostly have no access to the client. One place also means a new integration cannot leak by forgetting to filter. Breadcrumbs do not go through the span pipeline, so those are filtered separately. closes #23049 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent b68e0a5 commit 7e0a52f

43 files changed

Lines changed: 471 additions & 66 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.

packages/angular/src/tracing.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ import {
2424
import { CODE_FUNCTION_NAME, SENTRY_OP, URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';
2525
import { GENERAL_FUNCTION_SPAN_OP } from '@sentry/conventions/op';
2626
import type { Integration, Span } from '@sentry/core';
27-
import { debug, parseStringToURLObject, stripUrlQueryAndFragment, timestampInSeconds } from '@sentry/core';
27+
import {
28+
debug,
29+
parseStringToURLObject,
30+
stripUrlQueryAndFragment,
31+
timestampInSeconds,
32+
filterCollectedUrl,
33+
} from '@sentry/core';
2834
import type { Observable } from 'rxjs';
2935
import { Subscription } from 'rxjs';
3036
import { filter, tap } from 'rxjs/operators';
@@ -72,7 +78,7 @@ export function _updateSpanAttributesForParametrizedUrl(route: string, url: stri
7278
span.setAttributes({
7379
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.${op}.angular`,
7480
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
75-
[URL_FULL]: absoluteUrl,
81+
[URL_FULL]: filterCollectedUrl(absoluteUrl),
7682
[URL_PATH]: parseStringToURLObject(absoluteUrl)?.pathname,
7783
[URL_TEMPLATE]: route,
7884
});

packages/astro/src/server/middleware.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,
1313
spanToJSON,
1414
winterCGRequestToRequestData,
15+
filterCollectedUrl,
16+
filterCollectedUrlQuery,
1517
} from '@sentry/core';
1618
import {
1719
captureException,
@@ -214,7 +216,7 @@ async function instrumentRequestStartHttpServerSpan(
214216
[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method,
215217
// This is here for backwards compatibility, we used to set this here before
216218
method,
217-
[URL_FULL]: ctx.url.href,
219+
[URL_FULL]: filterCollectedUrl(ctx.url.href),
218220
[URL_PATH]: ctx.url.pathname,
219221
...httpHeadersToSpanAttributes(winterCGHeadersToDict(request.headers), client.getDataCollectionOptions()),
220222
};
@@ -223,7 +225,7 @@ async function instrumentRequestStartHttpServerSpan(
223225
attributes[HTTP_ROUTE] = parametrizedRoute;
224226
}
225227

226-
attributes[URL_QUERY] = getUrlQuery(ctx.url.search);
228+
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(ctx.url.search));
227229
attributes[URL_FRAGMENT] = getUrlFragment(ctx.url.hash);
228230

229231
const name = `${method} ${parametrizedRoute || ctx.url.pathname}`;

packages/aws-serverless/src/requestSpanOptions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {
2828
} from '@sentry/conventions/attributes';
2929
import { FAAS_FUNCTION_AWS_SPAN_OP } from '@sentry/conventions/op';
3030
import type { SpanAttributes, StartSpanOptions } from '@sentry/core';
31-
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
31+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, filterCollectedUrl } from '@sentry/core';
3232
import type { Context } from 'aws-lambda';
3333
import { ATTR_FAAS_EXECUTION, ATTR_FAAS_ID } from './semconv';
3434

@@ -75,7 +75,7 @@ function extractOtherEventFields(event: unknown): SpanAttributes {
7575
const answer: SpanAttributes = {};
7676
const fullUrl = extractFullUrl(event as ApiGatewayLikeEvent);
7777
if (fullUrl) {
78-
answer[URL_FULL] = fullUrl;
78+
answer[URL_FULL] = filterCollectedUrl(fullUrl);
7979
}
8080
return answer;
8181
}

packages/browser-utils/src/metrics/browserMetrics.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
setMeasurement,
1111
spanToJSON,
12+
filterCollectedUrl,
1213
} from '@sentry/core';
1314
import { htmlTreeAsString } from '../htmlTreeAsString';
1415
import { WINDOW } from '../types';
@@ -629,7 +630,7 @@ export function _addResourceSpans(
629630

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

632-
attributes[URL_FULL] = resourceUrl;
633+
attributes[URL_FULL] = filterCollectedUrl(resourceUrl);
633634

634635
_setResourceRequestAttributes(entry, attributes, [
635636
// 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
@@ -10,6 +10,7 @@ import {
1010
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
1111
startInactiveSpan,
1212
stripDataUrlContent,
13+
filterCollectedUrl,
1314
} from '@sentry/core';
1415

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

packages/browser/src/integrations/httpcontext.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
SEMANTIC_ATTRIBUTE_SENTRY_OP,
66
} from '@sentry/core/browser';
77
import { getHttpRequestData, WINDOW } from '../helpers';
8+
import { filterCollectedUrl } from '@sentry/core';
89
import { URL_FULL } from '@sentry/conventions/attributes';
910

1011
/**
@@ -59,7 +60,7 @@ export const httpContextIntegration = defineIntegration(() => {
5960
safeSetSpanJSONAttributes(span, {
6061
// Coerce empty string to undefined so the helper's nullish check drops it,
6162
// rather than writing an empty `url.full` attribute onto the span.
62-
[URL_FULL]: spanOp !== 'http.client' ? reqData.url : undefined,
63+
[URL_FULL]: spanOp !== 'http.client' ? filterCollectedUrl(reqData.url) : undefined,
6364
'http.request.header.user_agent': headers['User-Agent'],
6465
'http.request.header.referer': headers['Referer'],
6566
});

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';
@@ -392,7 +393,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption
392393

393394
const attributes = {
394395
...(urlObject?.pathname && { [URL_PATH]: urlObject.pathname }),
395-
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: urlObject.href }),
396+
...(urlObject && !isURLObjectRelative(urlObject) && { [URL_FULL]: filterCollectedUrl(urlObject.href) }),
396397
...finalStartSpanOptions.attributes,
397398
};
398399

packages/browser/src/tracing/request.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
timestampInSeconds,
3434
} from '@sentry/core/browser';
3535
import type { XhrHint } from '@sentry/browser-utils';
36+
import { filterCollectedUrl, filterCollectedUrlQuery } from '@sentry/core';
3637
import {
3738
addPerformanceInstrumentationHandler,
3839
addXhrInstrumentationHandler,
@@ -176,7 +177,7 @@ export function instrumentOutgoingRequests(client: Client, _options?: Partial<Re
176177
const host = fullUrl ? parseUrl(fullUrl).host : undefined;
177178
const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;
178179
createdSpan.setAttributes({
179-
[URL_FULL]: sanitizedFullUrl,
180+
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
180181
'server.address': host,
181182
});
182183

@@ -391,11 +392,11 @@ function xhrCallback(
391392
type: 'xhr',
392393
// eslint-disable-next-line typescript/no-deprecated
393394
[HTTP_METHOD]: method,
394-
[URL_FULL]: sanitizedFullUrl,
395+
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
395396
[SERVER_ADDRESS]: parsedUrl?.host,
396397
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
397398
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',
398-
[URL_QUERY]: getUrlQuery(parsedUrl?.search),
399+
[URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),
399400
[URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash),
400401
},
401402
})

packages/bun/src/integrations/bunserver.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
setHttpStatus,
1616
startSpan,
1717
withIsolationScope,
18+
filterCollectedUrl,
19+
filterCollectedUrlQuery,
1820
} from '@sentry/core';
1921
import type { ServeOptions } from 'bun';
2022
import {
@@ -289,13 +291,13 @@ function getSpanAttributesFromParsedUrl(
289291
};
290292

291293
if (parsedUrl) {
292-
attributes[URL_QUERY] = getUrlQuery(parsedUrl.search);
294+
attributes[URL_QUERY] = filterCollectedUrlQuery(getUrlQuery(parsedUrl.search));
293295
attributes[URL_FRAGMENT] = getUrlFragment(parsedUrl.hash);
294296
if (parsedUrl.pathname) {
295297
attributes[URL_PATH] = parsedUrl.pathname;
296298
}
297299
if (!isURLObjectRelative(parsedUrl)) {
298-
attributes[URL_FULL] = parsedUrl.href;
300+
attributes[URL_FULL] = filterCollectedUrl(parsedUrl.href);
299301
if (parsedUrl.port) {
300302
attributes[URL_PORT] = parsedUrl.port;
301303
}

packages/cloudflare/src/request.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,14 @@ export function wrapRequestHandlerWithInit(
8787
isolationScope.setClient(client);
8888

8989
const urlObject = parseStringToURLObject(request.url);
90-
const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);
90+
const [name, attributes] = getHttpSpanDetailsFromUrlObject(
91+
urlObject,
92+
'server',
93+
'auto.http.cloudflare',
94+
request,
95+
undefined,
96+
client,
97+
);
9198

9299
const contentLength = request.headers.get('content-length');
93100
if (contentLength) {

0 commit comments

Comments
 (0)