diff --git a/packages/cli/src/task-runners/task-runner-server.ts b/packages/cli/src/task-runners/task-runner-server.ts index 6e68c4fb3228c..80679f8c41a21 100644 --- a/packages/cli/src/task-runners/task-runner-server.ts +++ b/packages/cli/src/task-runners/task-runner-server.ts @@ -2,6 +2,7 @@ import { GlobalConfig } from '@n8n/config'; import { Service } from '@n8n/di'; import compression from 'compression'; import express from 'express'; +import { rateLimit as expressRateLimit } from 'express-rate-limit'; import { Logger } from 'n8n-core'; import * as a from 'node:assert/strict'; import { randomBytes } from 'node:crypto'; @@ -147,8 +148,16 @@ export class TaskRunnerServer { } private configureRoutes() { + const createRateLimiter = () => + expressRateLimit({ + windowMs: 1000, + limit: 5, + message: { message: 'Too many requests' }, + }); + this.app.use( this.upgradeEndpoint, + createRateLimiter(), // eslint-disable-next-line @typescript-eslint/unbound-method this.taskRunnerAuthController.authMiddleware, (req: TaskRunnerServerInitRequest, res: TaskRunnerServerInitResponse) => @@ -158,6 +167,7 @@ export class TaskRunnerServer { const authEndpoint = `${this.getEndpointBasePath()}/auth`; this.app.post( authEndpoint, + createRateLimiter(), send(async (req) => await this.taskRunnerAuthController.createGrantToken(req)), ); diff --git a/packages/cli/test/integration/runners/task-runner-server.test.ts b/packages/cli/test/integration/runners/task-runner-server.test.ts index 11d77b53fcdd2..6088af3525d67 100644 --- a/packages/cli/test/integration/runners/task-runner-server.test.ts +++ b/packages/cli/test/integration/runners/task-runner-server.test.ts @@ -19,4 +19,26 @@ describe('TaskRunnerServer', () => { await agent.get('/healthz').expect(200); }); }); + + describe('/runners/_ws', () => { + it('should return 429 when too many requests are made', async () => { + await agent.post('/runners/_ws').send({}).expect(401); + await agent.post('/runners/_ws').send({}).expect(401); + await agent.post('/runners/_ws').send({}).expect(401); + await agent.post('/runners/_ws').send({}).expect(401); + await agent.post('/runners/_ws').send({}).expect(401); + await agent.post('/runners/_ws').send({}).expect(429); + }); + }); + + describe('/runners/auth', () => { + it('should return 429 when too many requests are made', async () => { + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403); + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403); + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403); + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403); + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(403); + await agent.post('/runners/auth').send({ token: 'invalid' }).expect(429); + }); + }); });