From 019c59f10e52c0ca7af2483a28b62796977868cc Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 5 Jan 2026 14:58:26 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=AF=20fix:=20Actions=20Allowed=20Domai?= =?UTF-8?q?ns=20Handling=20(#11215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 fix: Update domain handling in ActionsInput components for SSRF validation - Refactored domain extraction logic in ActionsInput components to include protocol in the domain metadata for proper SSRF validation. - Ensured that the domain is constructed as `${parsedUrl.protocol}//${parsedUrl.hostname}` to enhance security and prevent potential vulnerabilities. This change improves the handling of user-provided domains and aligns with best practices for security in URL processing. * 🔧 fix: Include missing `actions` field in AppService configuration --- .../components/SidePanel/Agents/ActionsInput.tsx | 14 ++++++-------- .../components/SidePanel/Builder/ActionsInput.tsx | 12 +++++------- packages/data-provider/src/actions.ts | 5 +++-- packages/data-schemas/src/app/service.ts | 6 ++++-- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/client/src/components/SidePanel/Agents/ActionsInput.tsx b/client/src/components/SidePanel/Agents/ActionsInput.tsx index 9aeca38114..c6130d114a 100644 --- a/client/src/components/SidePanel/Agents/ActionsInput.tsx +++ b/client/src/components/SidePanel/Agents/ActionsInput.tsx @@ -121,12 +121,12 @@ export default function ActionsInput({ const action_id = action?.action_id; metadata.raw_spec = inputValue; const parsedUrl = new URL(data[0].domain); - const domain = parsedUrl.hostname; - if (!domain) { + if (!parsedUrl.hostname) { // alert user? return; } - metadata.domain = domain; + // Send protocol + hostname for proper SSRF validation (e.g., "http://192.168.1.1") + metadata.domain = `${parsedUrl.protocol}//${parsedUrl.hostname}`; const { type, saved_auth_fields } = authFormData; @@ -208,23 +208,21 @@ export default function ActionsInput({ htmlFor="schemaInput" className="text-token-text-primary whitespace-nowrap font-medium" > - Schema + {localize('com_ui_schema')} + {/* TODO: Implement examples functionality
- {/* */}
+ */}
diff --git a/client/src/components/SidePanel/Builder/ActionsInput.tsx b/client/src/components/SidePanel/Builder/ActionsInput.tsx index 84b72be682..7215ae3941 100644 --- a/client/src/components/SidePanel/Builder/ActionsInput.tsx +++ b/client/src/components/SidePanel/Builder/ActionsInput.tsx @@ -131,12 +131,12 @@ export default function ActionsInput({ const action_id = action?.action_id; metadata.raw_spec = inputValue; const parsedUrl = new URL(data[0].domain); - const domain = parsedUrl.hostname; - if (!domain) { + if (!parsedUrl.hostname) { // alert user? return; } - metadata.domain = domain; + // Send protocol + hostname for proper SSRF validation (e.g., "http://192.168.1.1") + metadata.domain = `${parsedUrl.protocol}//${parsedUrl.hostname}`; const { type, saved_auth_fields } = authFormData; @@ -221,22 +221,20 @@ export default function ActionsInput({ > {localize('com_ui_schema')} + {/* TODO: Implement examples functionality
- {/* */}
+ */}
diff --git a/packages/data-provider/src/actions.ts b/packages/data-provider/src/actions.ts index 70bd8fb325..c7566e479f 100644 --- a/packages/data-provider/src/actions.ts +++ b/packages/data-provider/src/actions.ts @@ -698,9 +698,9 @@ export function validateActionDomain( if (clientHasProtocol) { normalizedClientDomain = extractDomainFromUrl(clientProvidedDomain); } else { - // IP addresses inherit protocol from spec, domains default to https + // No protocol specified by client if (isIPAddress) { - // IPv6 addresses need brackets in URLs + // IPs inherit protocol from spec (for legitimate internal services) const ipVersion = isIP(normalizedClientHostname); const hostname = ipVersion === 6 && !clientHostname.startsWith('[') @@ -708,6 +708,7 @@ export function validateActionDomain( : clientHostname; normalizedClientDomain = `${specUrl.protocol}//${hostname}`; } else { + // Domain names default to HTTPS for security (forces explicit protocol) normalizedClientDomain = `https://${clientHostname}`; } } diff --git a/packages/data-schemas/src/app/service.ts b/packages/data-schemas/src/app/service.ts index e15a27e0b0..9f9f521f59 100644 --- a/packages/data-schemas/src/app/service.ts +++ b/packages/data-schemas/src/app/service.ts @@ -62,6 +62,7 @@ export const AppService = async (params?: { const mcpServersConfig = config.mcpServers || null; const mcpSettings = config.mcpSettings || null; + const actions = config.actions; const registration = config.registration ?? configDefaults.registration; const interfaceConfig = await loadDefaultInterface({ config, configDefaults }); const turnstileConfig = loadTurnstileConfig(config, configDefaults); @@ -74,6 +75,7 @@ export const AppService = async (params?: { memory, speech, balance, + actions, transactions, mcpConfig: mcpServersConfig, mcpSettings, @@ -103,9 +105,9 @@ export const AppService = async (params?: { const loadedEndpoints = loadEndpoints(config, agentsDefaults); - const appConfig = { + const appConfig: AppConfig = { ...defaultConfig, - fileConfig: config?.fileConfig, + fileConfig: config?.fileConfig as AppConfig['fileConfig'], secureImageLinks: config?.secureImageLinks, modelSpecs: processModelSpecs(config?.endpoints, config.modelSpecs, interfaceConfig), endpoints: loadedEndpoints,