diff --git a/packages/cli/src/executions/executions.controller.ts b/packages/cli/src/executions/executions.controller.ts index 9f7fd1b746..1085555604 100644 --- a/packages/cli/src/executions/executions.controller.ts +++ b/packages/cli/src/executions/executions.controller.ts @@ -8,6 +8,8 @@ import { NotFoundError } from '@/errors/response-errors/not-found.error'; import { parseRangeQuery } from './parse-range-query.middleware'; import type { User } from '@/databases/entities/User'; import type { Scope } from '@n8n/permissions'; +import { isPositiveInteger } from '@/utils'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @RestController('/executions') export class ExecutionsController { @@ -59,6 +61,10 @@ export class ExecutionsController { @Get('/:id') async getOne(req: ExecutionRequest.GetOne) { + if (!isPositiveInteger(req.params.id)) { + throw new BadRequestError('Execution ID is not a number'); + } + const workflowIds = await this.getAccessibleWorkflowIds(req.user, 'workflow:read'); if (workflowIds.length === 0) throw new NotFoundError('Execution not found'); diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts index f2d99eb0db..059dfec86b 100644 --- a/packages/cli/src/utils.ts +++ b/packages/cli/src/utils.ts @@ -92,3 +92,5 @@ export function rightDiff( * in switch statements or if/else chains. */ export const assertNever = (_value: never) => {}; + +export const isPositiveInteger = (maybeInt: string) => /^[1-9]\d*$/.test(maybeInt); diff --git a/packages/cli/test/unit/controllers/executions.controller.test.ts b/packages/cli/test/unit/controllers/executions.controller.test.ts index 06c64e1c18..046a5a0231 100644 --- a/packages/cli/test/unit/controllers/executions.controller.test.ts +++ b/packages/cli/test/unit/controllers/executions.controller.test.ts @@ -4,6 +4,7 @@ import { ExecutionsController } from '@/executions/executions.controller'; import type { ExecutionRequest, ExecutionSummaries } from '@/executions/execution.types'; import type { ExecutionService } from '@/executions/execution.service'; import type { WorkflowSharingService } from '@/workflows/workflowSharing.service'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; describe('ExecutionsController', () => { const executionService = mock(); @@ -20,6 +21,14 @@ describe('ExecutionsController', () => { jest.clearAllMocks(); }); + describe('getOne', () => { + it('should 400 when execution is not a number', async () => { + const req = mock({ params: { id: 'test' } }); + + await expect(executionsController.getOne(req)).rejects.toThrow(BadRequestError); + }); + }); + describe('getMany', () => { const NO_EXECUTIONS = { count: 0, estimated: false, results: [] };