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,