From ac8a988733751a49a3fbcf8fb6182a99f7e17f97 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 25 Feb 2026 14:29:11 -0800 Subject: [PATCH 1/5] Add protections for loop-bound injections --- .../components/evaluation/EvaluationRunner.ts | 11 +++++++ .../services/evaluations/EvaluatorRunner.ts | 5 +++ .../server/src/services/evaluations/index.ts | 33 ++++++++++++++++--- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/components/evaluation/EvaluationRunner.ts b/packages/components/evaluation/EvaluationRunner.ts index acde7944604..12458f0f1c9 100644 --- a/packages/components/evaluation/EvaluationRunner.ts +++ b/packages/components/evaluation/EvaluationRunner.ts @@ -88,6 +88,17 @@ export class EvaluationRunner { public async runEvaluations(data: ICommonObject) { const chatflowIds = JSON.parse(data.chatflowId) + + // Validate chatflowIds is an actual array to prevent DoS attacks + if (!Array.isArray(chatflowIds)) { + throw new Error('chatflowId must be a valid array') + } + + // Validate dataset.rows is an actual array to prevent DoS attacks + if (!data.dataset || !Array.isArray(data.dataset.rows)) { + throw new Error('dataset.rows must be a valid array') + } + const returnData: ICommonObject = {} returnData.evaluationId = data.evaluationId returnData.runDate = new Date() diff --git a/packages/server/src/services/evaluations/EvaluatorRunner.ts b/packages/server/src/services/evaluations/EvaluatorRunner.ts index 3f2a42081d7..5e3a4043130 100644 --- a/packages/server/src/services/evaluations/EvaluatorRunner.ts +++ b/packages/server/src/services/evaluations/EvaluatorRunner.ts @@ -17,6 +17,11 @@ export const runAdditionalEvaluators = async ( selectedEvaluators: string[], workspaceId: string ) => { + // Validate inputs are arrays and enforce size limits + if (!Array.isArray(actualOutputArray) || !Array.isArray(selectedEvaluators)) { + throw new Error('Invalid input: expected arrays') + } + const evaluationResults: any[] = [] const evaluatorDict: any = {} diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index fe0aae71b73..76783bf704d 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -72,14 +72,31 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str const row = appServer.AppDataSource.getRepository(Evaluation).create(newEval) row.average_metrics = JSON.stringify({}) + // Parse and validate evaluator arrays to prevent DoS attacks + const chatflowTypes = body.chatflowType ? JSON.parse(body.chatflowType) : [] + if (!Array.isArray(chatflowTypes)) { + throw new Error('chatflowType must be a valid array') + } + + const simpleEvaluators = body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + if (!Array.isArray(simpleEvaluators)) { + throw new Error('selectedSimpleEvaluators must be a valid array') + } + const additionalConfig: ICommonObject = { - chatflowTypes: body.chatflowType ? JSON.parse(body.chatflowType) : [], + chatflowTypes: chatflowTypes, datasetAsOneConversation: body.datasetAsOneConversation, - simpleEvaluators: body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + simpleEvaluators: simpleEvaluators } if (body.evaluationType === 'llm') { - additionalConfig.lLMEvaluators = body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] + const lLMEvaluators = body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] + + if (!Array.isArray(lLMEvaluators)) { + throw new Error('selectedLLMEvaluators must be a valid array') + } + + additionalConfig.lLMEvaluators = lLMEvaluators additionalConfig.llmConfig = { credentialId: body.credentialId, llm: body.llm, @@ -123,6 +140,12 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str // When chatflow has an APIKey const apiKeys: { chatflowId: string; apiKey: string }[] = [] const chatflowIds = JSON.parse(body.chatflowId) + + // Validate chatflowIds is an actual array to prevent DoS attacks + if (!Array.isArray(chatflowIds)) { + throw new Error('chatflowId must be a valid array') + } + for (let i = 0; i < chatflowIds.length; i++) { const chatflowId = chatflowIds[i] const cFlow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ @@ -246,7 +269,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str metricsArray, actualOutputArray, errorArray, - body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [], + additionalConfig.simpleEvaluators, workspaceId ) @@ -257,7 +280,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str if (body.evaluationType === 'llm') { resultRow.llmConfig = additionalConfig.llmConfig - resultRow.LLMEvaluators = body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] + resultRow.LLMEvaluators = additionalConfig.lLMEvaluators const llmEvaluatorMap: { evaluatorId: string; evaluator: any }[] = [] for (let i = 0; i < resultRow.LLMEvaluators.length; i++) { const evaluatorId = resultRow.LLMEvaluators[i] From b76bccc74f45bfb03bc08b0359d85d3c6acb9132 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 25 Feb 2026 14:35:19 -0800 Subject: [PATCH 2/5] Update packages/server/src/services/evaluations/index.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/server/src/services/evaluations/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 76783bf704d..841130492ec 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -78,7 +78,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str throw new Error('chatflowType must be a valid array') } - const simpleEvaluators = body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + const simpleEvaluators = body.selectedSimpleEvaluators && body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] if (!Array.isArray(simpleEvaluators)) { throw new Error('selectedSimpleEvaluators must be a valid array') } From 99a659d22126461b789035ba063acbbb6de554d7 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 25 Feb 2026 14:35:28 -0800 Subject: [PATCH 3/5] Update packages/server/src/services/evaluations/index.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- packages/server/src/services/evaluations/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 841130492ec..5822a66ee6b 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -90,7 +90,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str } if (body.evaluationType === 'llm') { - const lLMEvaluators = body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] + const lLMEvaluators = body.selectedLLMEvaluators && body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] if (!Array.isArray(lLMEvaluators)) { throw new Error('selectedLLMEvaluators must be a valid array') From b0eae70c329ec3ec2a96a6c42a205d9ee15b122a Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Wed, 25 Feb 2026 14:57:06 -0800 Subject: [PATCH 4/5] Add protections for loop-bound injections --- packages/server/src/services/evaluations/EvaluatorRunner.ts | 2 +- packages/server/src/services/evaluations/index.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/server/src/services/evaluations/EvaluatorRunner.ts b/packages/server/src/services/evaluations/EvaluatorRunner.ts index 5e3a4043130..716af83da03 100644 --- a/packages/server/src/services/evaluations/EvaluatorRunner.ts +++ b/packages/server/src/services/evaluations/EvaluatorRunner.ts @@ -17,7 +17,7 @@ export const runAdditionalEvaluators = async ( selectedEvaluators: string[], workspaceId: string ) => { - // Validate inputs are arrays and enforce size limits + // Validate that inputs are arrays if (!Array.isArray(actualOutputArray) || !Array.isArray(selectedEvaluators)) { throw new Error('Invalid input: expected arrays') } diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 5822a66ee6b..742c1f9fec9 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -78,7 +78,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str throw new Error('chatflowType must be a valid array') } - const simpleEvaluators = body.selectedSimpleEvaluators && body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + const simpleEvaluators = + body.selectedSimpleEvaluators && body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] if (!Array.isArray(simpleEvaluators)) { throw new Error('selectedSimpleEvaluators must be a valid array') } @@ -90,7 +91,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str } if (body.evaluationType === 'llm') { - const lLMEvaluators = body.selectedLLMEvaluators && body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] + const lLMEvaluators = + body.selectedLLMEvaluators && body.selectedLLMEvaluators.length > 0 ? JSON.parse(body.selectedLLMEvaluators) : [] if (!Array.isArray(lLMEvaluators)) { throw new Error('selectedLLMEvaluators must be a valid array') From 3602b37ca5dde5aea469ec983b028e6c50a9b054 Mon Sep 17 00:00:00 2001 From: christopherholland-workday Date: Thu, 26 Feb 2026 09:04:21 -0800 Subject: [PATCH 5/5] Add protections for loop-bound injections --- packages/components/evaluation/EvaluationRunner.ts | 2 -- packages/server/src/services/evaluations/index.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/components/evaluation/EvaluationRunner.ts b/packages/components/evaluation/EvaluationRunner.ts index 12458f0f1c9..b0b8c88eb99 100644 --- a/packages/components/evaluation/EvaluationRunner.ts +++ b/packages/components/evaluation/EvaluationRunner.ts @@ -89,12 +89,10 @@ export class EvaluationRunner { public async runEvaluations(data: ICommonObject) { const chatflowIds = JSON.parse(data.chatflowId) - // Validate chatflowIds is an actual array to prevent DoS attacks if (!Array.isArray(chatflowIds)) { throw new Error('chatflowId must be a valid array') } - // Validate dataset.rows is an actual array to prevent DoS attacks if (!data.dataset || !Array.isArray(data.dataset.rows)) { throw new Error('dataset.rows must be a valid array') } diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 742c1f9fec9..b658a74da76 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -72,7 +72,6 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str const row = appServer.AppDataSource.getRepository(Evaluation).create(newEval) row.average_metrics = JSON.stringify({}) - // Parse and validate evaluator arrays to prevent DoS attacks const chatflowTypes = body.chatflowType ? JSON.parse(body.chatflowType) : [] if (!Array.isArray(chatflowTypes)) { throw new Error('chatflowType must be a valid array') @@ -143,7 +142,6 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str const apiKeys: { chatflowId: string; apiKey: string }[] = [] const chatflowIds = JSON.parse(body.chatflowId) - // Validate chatflowIds is an actual array to prevent DoS attacks if (!Array.isArray(chatflowIds)) { throw new Error('chatflowId must be a valid array') }