Vulnerability: Monkshu is an enterprise application server for mobile apps (iOS and Android), responsive HTML 5 apps, and JSON API services. In version 2.90 and earlier, there is a reflected cross-site scripting vulnerability in frontend HTTP server. The attacker can send in a carefully crafted URL along with a known bug in the server which will cause a 500 error, and the response will then embed the URL provided by the hacker. The impact is moderate as the hacker must also be able to craft an HTTP request which should cause a 500 server error. None such requests are known as this point. The issue is patched in version 2.95. As a workaround, one may use a disk caching plugin.
Vulnerability ID: CVE-2021-32812
CWE: CWE-79
Severity score: 2.9
Project: https://github.com/TekMonksGitHub/monkshu
Published: 2021-08-02
File: frontend/server/server.js
Commit message: Fix for GHSA-hcpx-66hq-7g4x. Cross-site reflection
Commit author: TekMonksGitHub

Vulnerable version (before fix):
 function _sendFile(fileRequested, req, res, stats) { 			if (conf.enableGZIPEncoding && acceptEncodingHeader.includes("gzip") && mime && (!Array.isArray(mime) || Array.isArray(mime) && mime[1]) ) { 				res.writeHead(200, _getServerHeaders({ "Content-Type": Array.isArray(mime)?mime[0]:mime, "Content-Encoding": "gzip" }, stats)); 				rawStream.pipe(zlib.createGzip()).pipe(res) 				.on("error", err => _sendError(req, res, 500, `500: ${req.url}, Server error: ${err}`)) 				.on("end", _ => res.end()); 			} else { 				res.writeHead(200, mime ? _getServerHeaders({"Content-Type":Array.isArray(mime)?mime[0]:mime}, stats) : _getServerHeaders({}, stats)); 				rawStream.on("data", chunk => res.write(chunk, "binary")) 					.on("error", err => _sendError(req, res, 500, `500: ${req.url}, Server error: ${err}`)) 					.on("end", _ => res.end()); 			} 		}

Fixed version (after fix):
 function _sendFile(fileRequested, req, res, stats) { 			if (conf.enableGZIPEncoding && acceptEncodingHeader.includes("gzip") && mime && (!Array.isArray(mime) || Array.isArray(mime) && mime[1]) ) { 				res.writeHead(200, _getServerHeaders({ "Content-Type": Array.isArray(mime)?mime[0]:mime, "Content-Encoding": "gzip" }, stats)); 				rawStream.pipe(zlib.createGzip()).pipe(res) 				.on("error", err => _sendError(req, res, 500, `500: Error: ${err}`)) 				.on("end", _ => res.end()); 			} else { 				res.writeHead(200, mime ? _getServerHeaders({"Content-Type":Array.isArray(mime)?mime[0]:mime}, stats) : _getServerHeaders({}, stats)); 				rawStream.on("data", chunk => res.write(chunk, "binary")) 					.on("error", err => _sendError(req, res, 500, `500: Error: ${err}`)) 					.on("end", _ => res.end()); 			} 		}

Patch:
patch: @@ -131,12 +131,12 @@ function _sendFile(fileRequested, req, res, stats) {
 			if (conf.enableGZIPEncoding && acceptEncodingHeader.includes("gzip") && mime && (!Array.isArray(mime) || Array.isArray(mime) && mime[1]) ) {
 				res.writeHead(200, _getServerHeaders({ "Content-Type": Array.isArray(mime)?mime[0]:mime, "Content-Encoding": "gzip" }, stats));
 				rawStream.pipe(zlib.createGzip()).pipe(res)
-				.on("error", err => _sendError(req, res, 500, `500: ${req.url}, Server error: ${err}`))
+				.on("error", err => _sendError(req, res, 500, `500: Error: ${err}`))
 				.on("end", _ => res.end());
 			} else {
 				res.writeHead(200, mime ? _getServerHeaders({"Content-Type":Array.isArray(mime)?mime[0]:mime}, stats) : _getServerHeaders({}, stats));
 				rawStream.on("data", chunk => res.write(chunk, "binary"))
-					.on("error", err => _sendError(req, res, 500, `500: ${req.url}, Server error: ${err}`))
+					.on("error", err => _sendError(req, res, 500, `500: Error: ${err}`))
 					.on("end", _ => res.end());
 			}
 		}
path: frontend/server/server.js