From 468e5734a9ab02516430cc0dab5d7f2106dea950 Mon Sep 17 00:00:00 2001 From: Joe Boccanfuso <109477394+jbocce@users.noreply.github.com> Date: Wed, 29 Apr 2026 11:57:33 -0400 Subject: [PATCH] fix(config url): Hardening fetch options. (#5985) --- .../default/src/utils/secureConfigFetch.js | 23 +++++++--------- .../src/utils/secureConfigFetch.test.js | 26 +++++++++++++++---- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/extensions/default/src/utils/secureConfigFetch.js b/extensions/default/src/utils/secureConfigFetch.js index 079f994ae..63fbc5429 100644 --- a/extensions/default/src/utils/secureConfigFetch.js +++ b/extensions/default/src/utils/secureConfigFetch.js @@ -97,16 +97,14 @@ function resolveConfigFetchPolicy(rawUrl, policy = {}) { } async function fetchConfigJson(normalizedPolicy) { - const { normalizedUrl, isAuthenticated, isSameOrigin } = normalizedPolicy; - const response = isAuthenticated || isSameOrigin - ? await fetch(normalizedUrl) - : await fetch(normalizedUrl, { - method: 'GET', - mode: 'cors', - credentials: 'omit', - redirect: 'error', - referrerPolicy: 'no-referrer', - }); + const { normalizedUrl } = normalizedPolicy; + const response = await fetch(normalizedUrl, { + method: 'GET', + mode: 'cors', + credentials: 'same-origin', + redirect: 'error', + referrerPolicy: 'no-referrer', + }); if (!response.ok) { throw new Error(`Failed to fetch dynamic datasource configuration (${response.status})`); @@ -114,7 +112,4 @@ async function fetchConfigJson(normalizedPolicy) { return response.json(); } -export { - resolveConfigFetchPolicy, - fetchConfigJson, -}; +export { resolveConfigFetchPolicy, fetchConfigJson }; diff --git a/extensions/default/src/utils/secureConfigFetch.test.js b/extensions/default/src/utils/secureConfigFetch.test.js index 9a7f68aee..bf71b6d50 100644 --- a/extensions/default/src/utils/secureConfigFetch.test.js +++ b/extensions/default/src/utils/secureConfigFetch.test.js @@ -103,14 +103,14 @@ describe('secureConfigFetch', () => { expect.objectContaining({ method: 'GET', mode: 'cors', - credentials: 'omit', + credentials: 'same-origin', redirect: 'error', referrerPolicy: 'no-referrer', }) ); }); - it('uses simple fetch for unauthenticated same-origin requests', async () => { + it('uses hardened fetch options for unauthenticated same-origin requests', async () => { global.fetch.mockResolvedValue({ status: 200, ok: true, @@ -124,11 +124,18 @@ describe('secureConfigFetch', () => { }); expect(global.fetch).toHaveBeenCalledWith( - `${window.location.origin}/protected/config.json` + `${window.location.origin}/protected/config.json`, + expect.objectContaining({ + method: 'GET', + mode: 'cors', + credentials: 'same-origin', + redirect: 'error', + referrerPolicy: 'no-referrer', + }) ); }); - it('uses simple fetch in authenticated environments', async () => { + it('uses hardened fetch options in authenticated environments', async () => { global.fetch.mockResolvedValue({ status: 200, ok: true, @@ -141,7 +148,16 @@ describe('secureConfigFetch', () => { isSameOrigin: false, }); - expect(global.fetch).toHaveBeenCalledWith('https://trusted.example.com/config.json'); + expect(global.fetch).toHaveBeenCalledWith( + 'https://trusted.example.com/config.json', + expect.objectContaining({ + method: 'GET', + mode: 'cors', + credentials: 'same-origin', + redirect: 'error', + referrerPolicy: 'no-referrer', + }) + ); }); }); });