diff --git a/packages/core/src/utils/isSentryRequestUrl.ts b/packages/core/src/utils/isSentryRequestUrl.ts index 8cda9404164a..edcb6fe30591 100644 --- a/packages/core/src/utils/isSentryRequestUrl.ts +++ b/packages/core/src/utils/isSentryRequestUrl.ts @@ -32,7 +32,15 @@ function checkDsn(url: string, dsn: DsnComponents | undefined): boolean { return false; } - return dsn ? urlParts.host.includes(dsn.host) && /(^|&|\?)sentry_key=/.test(urlParts.search) : false; + if (!dsn) { + return false; + } + + return hostnameMatchesDsnHost(urlParts.hostname, dsn.host) && /(^|&|\?)sentry_key=/.test(urlParts.search); +} + +function hostnameMatchesDsnHost(hostname: string, dsnHost: string): boolean { + return hostname === dsnHost || (dsnHost.length > 0 && hostname.endsWith(`.${dsnHost}`)); } function removeTrailingSlash(str: string): string { diff --git a/packages/core/test/lib/utils/isSentryRequestUrl.test.ts b/packages/core/test/lib/utils/isSentryRequestUrl.test.ts index 806165fb52be..e8aeef78b631 100644 --- a/packages/core/test/lib/utils/isSentryRequestUrl.test.ts +++ b/packages/core/test/lib/utils/isSentryRequestUrl.test.ts @@ -46,4 +46,24 @@ describe('isSentryRequestUrl', () => { it('handles undefined client', () => { expect(isSentryRequestUrl('http://sentry-dsn.com/my-url?sentry_key=123', undefined)).toBe(false); }); + + it('does not treat attacker-controlled hostnames that merely contain the DSN host as Sentry URLs', () => { + const dsnHost = 'o123456.ingest.sentry.io'; + const client = { + getOptions: () => ({ tunnel: '' }), + getDsn: () => ({ host: dsnHost }), + } as unknown as Client; + + expect(isSentryRequestUrl(`https://${dsnHost}.attacker.com/exfil?sentry_key=fake&data=stolen`, client)).toBe(false); + }); + + it('still matches legitimate subdomains of the DSN host', () => { + const dsnHost = 'ingest.sentry.io'; + const client = { + getOptions: () => ({ tunnel: '' }), + getDsn: () => ({ host: dsnHost }), + } as unknown as Client; + + expect(isSentryRequestUrl('https://o123456.ingest.sentry.io/api/1/store/?sentry_key=abc', client)).toBe(true); + }); });