From f174afdf5203085e854dc8af832cf54ef4372522 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 4 Mar 2026 11:07:56 -0800 Subject: [PATCH 1/3] Stop text-to-speach endpoint from accepting arbitrary creds --- packages/components/cookies.txt | 7 +++++++ .../server/src/controllers/text-to-speech/index.ts | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 packages/components/cookies.txt diff --git a/packages/components/cookies.txt b/packages/components/cookies.txt new file mode 100644 index 00000000000..838518d7d6c --- /dev/null +++ b/packages/components/cookies.txt @@ -0,0 +1,7 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_localhost FALSE / FALSE 0 connect.sid s%3Acwjbi1guxLcnar0s1aVCP5bMBvSsyX4f.VHFJfS8WHyPbC2xM8Src7AU9MAB2kF15w%2F%2FY7G2wwIc +#HttpOnly_localhost FALSE / FALSE 0 refreshToken eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwZDQxNjQ2LTk1YmYtNDM4ZS1iZGE2LWU3ZjlkY2QyZjcxZSIsInVzZXJuYW1lIjoiQ2hyaXMgQWRtaW4iLCJtZXRhIjoiMDdjNzAwNGU2NzQ5OTYyN2YyNzVmY2FkNzBlMDZmMTg6MTlmODhjNTQzNjNmZWRjODljYjQ1MmVkZTYzN2E5ODliMDRlY2JiNDFkYzFjZTY2ZGM3YzMzNjk0MzAxYmM5MzQ2YzEzZjdiYjk5ZGI1YmFkYmY0NGM1ZTI2M2NhYzAzMTY0NjAxYWQ0YTk4NWM0OGM2YWVmMTAxOTZmN2JkOGYxYmEzMzg2NzkzODg4NDI4YjBiNDEwOGMxZTY2OTliNiIsImlhdCI6MTc3MjY1MTAzNCwibmJmIjoxNzcyNjUxMDM0LCJleHAiOjE3NzUyNDMwMzQsImF1ZCI6IkZsb3dpc2UiLCJpc3MiOiJGbG93aXNlIn0.8CVAjXXGxskieocmhfVt6mvD0hgiToketbQI2q6_vAs +#HttpOnly_localhost FALSE / FALSE 0 token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwZDQxNjQ2LTk1YmYtNDM4ZS1iZGE2LWU3ZjlkY2QyZjcxZSIsInVzZXJuYW1lIjoiQ2hyaXMgQWRtaW4iLCJtZXRhIjoiZmRjYjM4MWIxMTVjMzI1Zjc1MTBlYzE5YzdjYjM4Y2U6OTI0ZDg2YjRjMjllNTdjNDVmODYxOTNmNmVmNDQxMDEyNDkzYjhiMDkzNTZjYjY1YTJiY2RjNWZiMGJjMDMzOGJhZmNiZTUxN2I4MGNiZDg4ZjRmZGU3MWYxNjY2N2ExMjViOWJlMDE4NDIyYmMxYTAwMTVhYjNmZjQ4YjEwZWNlOGI2OGJjZmVhZjdlMjlmZGQ4OTRjYjAzMmYyMDEyMiIsImlhdCI6MTc3MjY1MTAzNCwibmJmIjoxNzcyNjUxMDM0LCJleHAiOjE3NzI2NzI2MzQsImF1ZCI6IkZsb3dpc2UiLCJpc3MiOiJGbG93aXNlIn0.rxhXXvWeTf8S3ggIpApR6NnHOK-ZyW_fJE3qAYxGb3c diff --git a/packages/server/src/controllers/text-to-speech/index.ts b/packages/server/src/controllers/text-to-speech/index.ts index af92713a87e..db5500c6c7e 100644 --- a/packages/server/src/controllers/text-to-speech/index.ts +++ b/packages/server/src/controllers/text-to-speech/index.ts @@ -3,6 +3,7 @@ import { convertTextToSpeechStream } from 'flowise-components' import { StatusCodes } from 'http-status-codes' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import chatflowsService from '../../services/chatflows' +import credentialsService from '../../services/credentials' import textToSpeechService from '../../services/text-to-speech' import { databaseEntities } from '../../utils' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' @@ -56,6 +57,17 @@ const generateTextToSpeech = async (req: Request, res: Response) => { voice = providerConfig.voice model = providerConfig.model } else { + // Body-supplied credentials require the caller to be authenticated + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + return res.status(StatusCodes.UNAUTHORIZED).json({ message: 'Authentication required' }) + } + if (!bodyCredentialId) { + return res.status(StatusCodes.BAD_REQUEST).json({ message: 'credentialId not provided' }) + } + // Verify the credential belongs to the authenticated user's workspace — + // throws NOT_FOUND if the credential doesn't exist or belongs to another workspace + await credentialsService.getCredentialById(bodyCredentialId, workspaceId) // Use TTS config from request body provider = bodyProvider credentialId = bodyCredentialId @@ -80,8 +92,6 @@ const generateTextToSpeech = async (req: Request, res: Response) => { res.setHeader('Content-Type', 'text/event-stream') res.setHeader('Cache-Control', 'no-cache') res.setHeader('Connection', 'keep-alive') - res.setHeader('Access-Control-Allow-Origin', '*') - res.setHeader('Access-Control-Allow-Headers', 'Cache-Control') const appServer = getRunningExpressApp() const options = { From 97d0c8eea850deb58a1972befac04865dad6ec8d Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 4 Mar 2026 11:11:38 -0800 Subject: [PATCH 2/3] Stop text-to-speach endpoint from accepting arbitrary creds --- packages/components/cookies.txt | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 packages/components/cookies.txt diff --git a/packages/components/cookies.txt b/packages/components/cookies.txt deleted file mode 100644 index 838518d7d6c..00000000000 --- a/packages/components/cookies.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Netscape HTTP Cookie File -# https://curl.se/docs/http-cookies.html -# This file was generated by libcurl! Edit at your own risk. - -#HttpOnly_localhost FALSE / FALSE 0 connect.sid s%3Acwjbi1guxLcnar0s1aVCP5bMBvSsyX4f.VHFJfS8WHyPbC2xM8Src7AU9MAB2kF15w%2F%2FY7G2wwIc -#HttpOnly_localhost FALSE / FALSE 0 refreshToken eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwZDQxNjQ2LTk1YmYtNDM4ZS1iZGE2LWU3ZjlkY2QyZjcxZSIsInVzZXJuYW1lIjoiQ2hyaXMgQWRtaW4iLCJtZXRhIjoiMDdjNzAwNGU2NzQ5OTYyN2YyNzVmY2FkNzBlMDZmMTg6MTlmODhjNTQzNjNmZWRjODljYjQ1MmVkZTYzN2E5ODliMDRlY2JiNDFkYzFjZTY2ZGM3YzMzNjk0MzAxYmM5MzQ2YzEzZjdiYjk5ZGI1YmFkYmY0NGM1ZTI2M2NhYzAzMTY0NjAxYWQ0YTk4NWM0OGM2YWVmMTAxOTZmN2JkOGYxYmEzMzg2NzkzODg4NDI4YjBiNDEwOGMxZTY2OTliNiIsImlhdCI6MTc3MjY1MTAzNCwibmJmIjoxNzcyNjUxMDM0LCJleHAiOjE3NzUyNDMwMzQsImF1ZCI6IkZsb3dpc2UiLCJpc3MiOiJGbG93aXNlIn0.8CVAjXXGxskieocmhfVt6mvD0hgiToketbQI2q6_vAs -#HttpOnly_localhost FALSE / FALSE 0 token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjAwZDQxNjQ2LTk1YmYtNDM4ZS1iZGE2LWU3ZjlkY2QyZjcxZSIsInVzZXJuYW1lIjoiQ2hyaXMgQWRtaW4iLCJtZXRhIjoiZmRjYjM4MWIxMTVjMzI1Zjc1MTBlYzE5YzdjYjM4Y2U6OTI0ZDg2YjRjMjllNTdjNDVmODYxOTNmNmVmNDQxMDEyNDkzYjhiMDkzNTZjYjY1YTJiY2RjNWZiMGJjMDMzOGJhZmNiZTUxN2I4MGNiZDg4ZjRmZGU3MWYxNjY2N2ExMjViOWJlMDE4NDIyYmMxYTAwMTVhYjNmZjQ4YjEwZWNlOGI2OGJjZmVhZjdlMjlmZGQ4OTRjYjAzMmYyMDEyMiIsImlhdCI6MTc3MjY1MTAzNCwibmJmIjoxNzcyNjUxMDM0LCJleHAiOjE3NzI2NzI2MzQsImF1ZCI6IkZsb3dpc2UiLCJpc3MiOiJGbG93aXNlIn0.rxhXXvWeTf8S3ggIpApR6NnHOK-ZyW_fJE3qAYxGb3c From 981ea4731521153ab4b380833d66145c77a9ba33 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Mon, 9 Mar 2026 10:19:43 -0700 Subject: [PATCH 3/3] Hardcoded CORS wildcard on TTS endpoint enables cross-origin credential abuse from any webpage --- .../server/src/controllers/text-to-speech/index.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/server/src/controllers/text-to-speech/index.ts b/packages/server/src/controllers/text-to-speech/index.ts index db5500c6c7e..4346d460269 100644 --- a/packages/server/src/controllers/text-to-speech/index.ts +++ b/packages/server/src/controllers/text-to-speech/index.ts @@ -3,7 +3,6 @@ import { convertTextToSpeechStream } from 'flowise-components' import { StatusCodes } from 'http-status-codes' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import chatflowsService from '../../services/chatflows' -import credentialsService from '../../services/credentials' import textToSpeechService from '../../services/text-to-speech' import { databaseEntities } from '../../utils' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' @@ -57,17 +56,6 @@ const generateTextToSpeech = async (req: Request, res: Response) => { voice = providerConfig.voice model = providerConfig.model } else { - // Body-supplied credentials require the caller to be authenticated - const workspaceId = req.user?.activeWorkspaceId - if (!workspaceId) { - return res.status(StatusCodes.UNAUTHORIZED).json({ message: 'Authentication required' }) - } - if (!bodyCredentialId) { - return res.status(StatusCodes.BAD_REQUEST).json({ message: 'credentialId not provided' }) - } - // Verify the credential belongs to the authenticated user's workspace — - // throws NOT_FOUND if the credential doesn't exist or belongs to another workspace - await credentialsService.getCredentialById(bodyCredentialId, workspaceId) // Use TTS config from request body provider = bodyProvider credentialId = bodyCredentialId