From 903c94e913e9e3cff7d956f673eb2bfd1feeb5a9 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Fri, 14 Aug 2026 12:59:11 -0700 Subject: [PATCH] fix(dataverse): strip the bearer token when a request redirects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The host allowlist added alongside the connector work only constrains the initial destination. `secureFetchWithPinnedIP` follows redirects and keeps the `Authorization` header unless a tool opts out, so a redirect away from an allowed Dataverse origin would forward the caller's OAuth token to whatever host answers. Dataverse redirects in normal operation — file downloads hand back a signed storage URL, and environment hosts move between regional origins — so this is reachable without a compromised environment URL. Sets `stripAuthOnRedirect` on all 18 Dataverse tools, matching the existing GitHub job-logs and Windchill precedent. --- apps/sim/tools/microsoft_dataverse/associate.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/create_multiple.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/create_record.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/delete_record.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/disassociate.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/download_file.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/execute_action.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/execute_function.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/fetchxml_query.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/get_entity_metadata.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/get_record.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/list_records.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/search.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/update_multiple.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/update_record.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/upload_file.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/upsert_record.ts | 6 ++++++ apps/sim/tools/microsoft_dataverse/whoami.ts | 6 ++++++ 18 files changed, 108 insertions(+) diff --git a/apps/sim/tools/microsoft_dataverse/associate.ts b/apps/sim/tools/microsoft_dataverse/associate.ts index 32978ef631..e901f4061a 100644 --- a/apps/sim/tools/microsoft_dataverse/associate.ts +++ b/apps/sim/tools/microsoft_dataverse/associate.ts @@ -80,6 +80,12 @@ export const dataverseAssociateTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})/${params.navigationProperty.trim()}/$ref` }, method: (params) => (params.navigationType === 'single' ? 'PUT' : 'POST'), + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/create_multiple.ts b/apps/sim/tools/microsoft_dataverse/create_multiple.ts index 12db7cdc4d..3fe1101a37 100644 --- a/apps/sim/tools/microsoft_dataverse/create_multiple.ts +++ b/apps/sim/tools/microsoft_dataverse/create_multiple.ts @@ -62,6 +62,12 @@ export const dataverseCreateMultipleTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}/Microsoft.Dynamics.CRM.CreateMultiple` }, method: 'POST', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/create_record.ts b/apps/sim/tools/microsoft_dataverse/create_record.ts index 35240b41f2..33ed6d0280 100644 --- a/apps/sim/tools/microsoft_dataverse/create_record.ts +++ b/apps/sim/tools/microsoft_dataverse/create_record.ts @@ -55,6 +55,12 @@ export const dataverseCreateRecordTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}` }, method: 'POST', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/delete_record.ts b/apps/sim/tools/microsoft_dataverse/delete_record.ts index f9bac250fe..c0fe5aafaa 100644 --- a/apps/sim/tools/microsoft_dataverse/delete_record.ts +++ b/apps/sim/tools/microsoft_dataverse/delete_record.ts @@ -53,6 +53,12 @@ export const dataverseDeleteRecordTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})` }, method: 'DELETE', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/disassociate.ts b/apps/sim/tools/microsoft_dataverse/disassociate.ts index d74f5a349c..82e284a245 100644 --- a/apps/sim/tools/microsoft_dataverse/disassociate.ts +++ b/apps/sim/tools/microsoft_dataverse/disassociate.ts @@ -74,6 +74,12 @@ export const dataverseDisassociateTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${entitySetName}(${recordId})/${navigationProperty}/$ref` }, method: 'DELETE', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/download_file.ts b/apps/sim/tools/microsoft_dataverse/download_file.ts index 155374fef2..d6f322bf72 100644 --- a/apps/sim/tools/microsoft_dataverse/download_file.ts +++ b/apps/sim/tools/microsoft_dataverse/download_file.ts @@ -60,6 +60,12 @@ export const dataverseDownloadFileTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})/${params.fileColumn.trim()}/$value` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/execute_action.ts b/apps/sim/tools/microsoft_dataverse/execute_action.ts index 1a427bb151..4cad4931cc 100644 --- a/apps/sim/tools/microsoft_dataverse/execute_action.ts +++ b/apps/sim/tools/microsoft_dataverse/execute_action.ts @@ -78,6 +78,12 @@ export const dataverseExecuteActionTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${actionName}` }, method: 'POST', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/execute_function.ts b/apps/sim/tools/microsoft_dataverse/execute_function.ts index 4457af4113..40a1392ce7 100644 --- a/apps/sim/tools/microsoft_dataverse/execute_function.ts +++ b/apps/sim/tools/microsoft_dataverse/execute_function.ts @@ -83,6 +83,12 @@ export const dataverseExecuteFunctionTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${functionName}${paramStr}${querySuffix}` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/fetchxml_query.ts b/apps/sim/tools/microsoft_dataverse/fetchxml_query.ts index 0e6fd37fed..fdad61edb5 100644 --- a/apps/sim/tools/microsoft_dataverse/fetchxml_query.ts +++ b/apps/sim/tools/microsoft_dataverse/fetchxml_query.ts @@ -57,6 +57,12 @@ export const dataverseFetchXmlQueryTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}?fetchXml=${encodedFetchXml}` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/get_entity_metadata.ts b/apps/sim/tools/microsoft_dataverse/get_entity_metadata.ts index 2dcb4d87eb..82ec14e0f3 100644 --- a/apps/sim/tools/microsoft_dataverse/get_entity_metadata.ts +++ b/apps/sim/tools/microsoft_dataverse/get_entity_metadata.ts @@ -76,6 +76,12 @@ export const dataverseGetEntityMetadataTool: ToolConfig< return `${baseUrl}/api/data/v9.2/EntityDefinitions(LogicalName='${entityLogicalName}')${query}` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/get_record.ts b/apps/sim/tools/microsoft_dataverse/get_record.ts index 344405ba28..039179d77d 100644 --- a/apps/sim/tools/microsoft_dataverse/get_record.ts +++ b/apps/sim/tools/microsoft_dataverse/get_record.ts @@ -71,6 +71,12 @@ export const dataverseGetRecordTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})${query}` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0', diff --git a/apps/sim/tools/microsoft_dataverse/list_records.ts b/apps/sim/tools/microsoft_dataverse/list_records.ts index b79bea0508..fc5ff1f6f4 100644 --- a/apps/sim/tools/microsoft_dataverse/list_records.ts +++ b/apps/sim/tools/microsoft_dataverse/list_records.ts @@ -93,6 +93,12 @@ export const dataverseListRecordsTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}${query}` }, method: 'GET', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => { // Dataverse ignores $top entirely when Prefer: odata.maxpagesize is also sent, so the // page-size preference is only applied when the caller hasn't requested an explicit $top. diff --git a/apps/sim/tools/microsoft_dataverse/search.ts b/apps/sim/tools/microsoft_dataverse/search.ts index d313074925..e2d0b28c3d 100644 --- a/apps/sim/tools/microsoft_dataverse/search.ts +++ b/apps/sim/tools/microsoft_dataverse/search.ts @@ -98,6 +98,12 @@ export const dataverseSearchTool: ToolConfig ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/update_multiple.ts b/apps/sim/tools/microsoft_dataverse/update_multiple.ts index d0702c1b1c..84f411d80b 100644 --- a/apps/sim/tools/microsoft_dataverse/update_multiple.ts +++ b/apps/sim/tools/microsoft_dataverse/update_multiple.ts @@ -62,6 +62,12 @@ export const dataverseUpdateMultipleTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}/Microsoft.Dynamics.CRM.UpdateMultiple` }, method: 'POST', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/update_record.ts b/apps/sim/tools/microsoft_dataverse/update_record.ts index 8bf3b1ff79..872f5e9461 100644 --- a/apps/sim/tools/microsoft_dataverse/update_record.ts +++ b/apps/sim/tools/microsoft_dataverse/update_record.ts @@ -60,6 +60,12 @@ export const dataverseUpdateRecordTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})` }, method: 'PATCH', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/upload_file.ts b/apps/sim/tools/microsoft_dataverse/upload_file.ts index a8025fe091..3bc72fbe88 100644 --- a/apps/sim/tools/microsoft_dataverse/upload_file.ts +++ b/apps/sim/tools/microsoft_dataverse/upload_file.ts @@ -70,6 +70,12 @@ export const dataverseUploadFileTool: ToolConfig< request: { url: '/api/tools/microsoft-dataverse/upload-file', method: 'POST', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: () => ({ 'Content-Type': 'application/json', }), diff --git a/apps/sim/tools/microsoft_dataverse/upsert_record.ts b/apps/sim/tools/microsoft_dataverse/upsert_record.ts index 04f82356f2..9642cecc72 100644 --- a/apps/sim/tools/microsoft_dataverse/upsert_record.ts +++ b/apps/sim/tools/microsoft_dataverse/upsert_record.ts @@ -61,6 +61,12 @@ export const dataverseUpsertRecordTool: ToolConfig< return `${baseUrl}/api/data/v9.2/${params.entitySetName.trim()}(${params.recordId.trim()})` }, method: 'PATCH', + /** + * Dataverse endpoints redirect (file downloads issue a signed storage URL, + * and environment hosts redirect between regional origins), so drop the + * bearer token rather than forward it to whatever origin answers. + */ + stripAuthOnRedirect: true, headers: (params) => ({ Authorization: `Bearer ${params.accessToken}`, 'Content-Type': 'application/json', diff --git a/apps/sim/tools/microsoft_dataverse/whoami.ts b/apps/sim/tools/microsoft_dataverse/whoami.ts index d78174ecd4..95e2969b89 100644 --- a/apps/sim/tools/microsoft_dataverse/whoami.ts +++ b/apps/sim/tools/microsoft_dataverse/whoami.ts @@ -39,6 +39,12 @@ export const dataverseWhoAmITool: ToolConfig ({ Authorization: `Bearer ${params.accessToken}`, 'OData-MaxVersion': '4.0',