From 4856fdda2fac1408ff053fd3dad1a9ffe137af4e Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Fri, 26 Mar 2021 14:53:53 +0200 Subject: [PATCH] Fix path traversal bug in router (#2398) * fix path traversal bug in router Signed-off-by: Jari Kolehmainen * add tests Signed-off-by: Jari Kolehmainen --- src/main/__test__/router.test.ts | 40 ++++++++++++++++++++++++++++++++ src/main/router.ts | 16 ++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/main/__test__/router.test.ts diff --git a/src/main/__test__/router.test.ts b/src/main/__test__/router.test.ts new file mode 100644 index 0000000000..8c2fa9c822 --- /dev/null +++ b/src/main/__test__/router.test.ts @@ -0,0 +1,40 @@ +import { Router } from "../router"; + +const staticRoot = __dirname; + +class TestRouter extends Router { + protected resolveStaticRootPath() { + return staticRoot; + } +} + +describe("Router", () => { + it("blocks path traversal attacks", async () => { + const router = new TestRouter(); + const res = { + statusCode: 200, + end: jest.fn() + }; + + await router.handleStaticFile("../index.ts", res as any, {} as any, 0); + + expect(res.statusCode).toEqual(404); + }); + + it("serves files under static root", async () => { + const router = new TestRouter(); + const res = { + statusCode: 200, + write: jest.fn(), + setHeader: jest.fn(), + end: jest.fn() + }; + const req = { + url: "" + }; + + await router.handleStaticFile("router.test.ts", res as any, req as any, 0); + + expect(res.statusCode).toEqual(200); + }); +}); diff --git a/src/main/router.ts b/src/main/router.ts index bb49aacdab..6fa14e1444 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -40,10 +40,16 @@ export interface LensApiRequest

{ export class Router { protected router: any; + protected staticRootPath: string; public constructor() { this.router = new Call.Router(); this.addRoutes(); + this.staticRootPath = this.resolveStaticRootPath(); + } + + protected resolveStaticRootPath() { + return path.resolve(__static); } public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise { @@ -102,7 +108,15 @@ export class Router { } async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) { - const asset = path.join(__static, filePath); + const asset = path.join(this.staticRootPath, filePath); + const normalizedFilePath = path.resolve(asset); + + if (!normalizedFilePath.startsWith(this.staticRootPath)) { + res.statusCode = 404; + res.end(); + + return; + } try { const filename = path.basename(req.url);