From 9e2f9e21e904c4a319e84265da7ef03b0a8e343a Mon Sep 17 00:00:00 2001 From: Sheogorath Date: Sat, 9 Apr 2022 02:36:30 +0200 Subject: [PATCH] fix(imageRouter): Fix enumerable image upload issue This patch adds an own filename function for `formidable`, which will make sure to generate a random file name, using UUIDv4. This should resolve GHSA-q6vv-2q26-j7rx. This change is required due to a change in behaviour from version 1 to version 2 of formidable. Formidable version 2 will generate predictable filenames by default, which results in potential access to images, that were uploaded while formidable v2 was used in Hedgedoc. This affects the versions `1.9.1` and `1.9.2`. Files generated previous to this commit will look like this: ``` . 38e56506ec2dcab52e9282c00.jpg 38e56506ec2dcab52e9282c01.jpg 38e56506ec2dcab52e9282c02.jpg ``` After this patch it'll look like this: ``` . a67f36b8-9afb-43c2-9ef2-a567a77d8628.jpg 56b3d5d0-c586-4679-9ae6-d2044843c2cd.jpg 2af727ac-a2d4-4aad-acb5-73596c2a7eb6.jpg ``` This patch was implemented using `uuid` since we already utilise this package elsewhere in the project as well as using a secure function to generate random strings. UUIDv4 is ideal for that. In order to be consumable by formidable, it was wrapped in a function that makes sure to keep the file extension. This vulnerability was reported by Matias from [NCSC-FI](https://www.kyberturvallisuuskeskus.fi/). References: https://github.com/node-formidable/formidable/blob/v2-latest/src/Formidable.js#L574 https://github.com/node-formidable/formidable/issues/808#issuecomment-1007090762 https://www.npmjs.com/package/uuid --- lib/web/imageRouter/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/web/imageRouter/index.js b/lib/web/imageRouter/index.js index 7e555f9cd..ca0ebd00e 100644 --- a/lib/web/imageRouter/index.js +++ b/lib/web/imageRouter/index.js @@ -4,6 +4,7 @@ const Router = require('express').Router const formidable = require('formidable') const path = require('path') const fs = require('fs') +const { v4: uuidv4 } = require('uuid'); const os = require('os') const rimraf = require('rimraf') const isSvg = require('is-svg') @@ -70,7 +71,13 @@ imageRouter.post('/uploadimage', function (req, res) { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hedgedoc-')) const form = formidable({ keepExtensions: true, - uploadDir: tmpDir + uploadDir: tmpDir, + filename: function(filename, ext) { + if (typeof ext !== "string") { + ext = ".invalid" + } + return uuidv4() + ext + } }) form.parse(req, async function (err, fields, files) {