From 78201ce9df67b82711eae51b1e6b89880cd899d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Medeiros?= Date: Tue, 5 Mar 2019 14:14:58 -0500 Subject: [PATCH] fix: prevent HTML injection in the cockpit (#1381) --- packages/embark/src/lib/core/logger.js | 2 ++ packages/embark/src/lib/modules/console/index.ts | 7 ++++++- .../embark/src/lib/modules/process_logs_api/index.js | 9 ++++++++- packages/embark/src/lib/utils/escapeHtml.js | 12 ++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 packages/embark/src/lib/utils/escapeHtml.js diff --git a/packages/embark/src/lib/core/logger.js b/packages/embark/src/lib/core/logger.js index b02781f39..4467e178b 100644 --- a/packages/embark/src/lib/core/logger.js +++ b/packages/embark/src/lib/core/logger.js @@ -1,6 +1,7 @@ require('colors'); let fs = require('./fs.js'); const date = require('date-and-time'); +const escapeHtml = require('../utils/escapeHtml'); const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss:SSS'; const LOG_REGEX = new RegExp(/\[(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d:\d\d\d)\] (?:\[(\w*)\]:?)?\s?\s?(.*)/gmi); @@ -71,6 +72,7 @@ Logger.prototype.registerAPICall = function (plugins) { '/embark-api/logs', (ws, _req) => { self.events.on("log", function (logLevel, logMsg) { + logMsg = escapeHtml(logMsg); ws.send(JSON.stringify({msg: logMsg, msg_clear: logMsg.stripColors, logLevel: logLevel}), () => {}); }); } diff --git a/packages/embark/src/lib/modules/console/index.ts b/packages/embark/src/lib/modules/console/index.ts index 6764d2eb4..7721ff864 100644 --- a/packages/embark/src/lib/modules/console/index.ts +++ b/packages/embark/src/lib/modules/console/index.ts @@ -1,6 +1,7 @@ /*globals __*/ const env = require("../../core/env"); const utils = require("../../utils/utils"); +const escapeHtml = require("../../utils/escapeHtml"); import { Callback } from "embark"; const stringify = require("json-stringify-safe"); import { waterfall } from "async"; @@ -102,8 +103,12 @@ class Console { let response = result; if (typeof result !== "string") { response = stringify(result, utils.jsonFunctionReplacer, 2); + this.logger.info(response); + } else { + // Avoid HTML injection in the Cockpit + this.logger.info(response); + response = escapeHtml(response); } - this.logger.info(response); return res.send({ result: response }); }); }); diff --git a/packages/embark/src/lib/modules/process_logs_api/index.js b/packages/embark/src/lib/modules/process_logs_api/index.js index 95d38d508..0f7f2cd94 100644 --- a/packages/embark/src/lib/modules/process_logs_api/index.js +++ b/packages/embark/src/lib/modules/process_logs_api/index.js @@ -1,4 +1,5 @@ const LogHandler = require('../../utils/logHandler'); +const escapeHtml = require('../../utils/escapeHtml'); class ProcessLogsApi { constructor({embark, processName, silent}) { @@ -18,6 +19,9 @@ class ProcessLogsApi { apiRoute, (ws, _req) => { this.events.on('process-log-' + this.processName, function (log) { + log.msg = escapeHtml(log.msg); + log.msg_clear = escapeHtml(log.msg_clear); + ws.send(JSON.stringify(log), () => {}); }); } @@ -28,7 +32,10 @@ class ProcessLogsApi { (req, res) => { let limit = parseInt(req.query.limit, 10); if (!Number.isInteger(limit)) limit = 0; - const result = this.logHandler.logs.slice(limit * -1); + const result = this.logHandler.logs + .slice(limit * -1) + .map(msg => escapeHtml(msg)); + res.send(JSON.stringify(result)); } ); diff --git a/packages/embark/src/lib/utils/escapeHtml.js b/packages/embark/src/lib/utils/escapeHtml.js new file mode 100644 index 000000000..25154b595 --- /dev/null +++ b/packages/embark/src/lib/utils/escapeHtml.js @@ -0,0 +1,12 @@ +function escapeHtml(message) { + if(typeof message !== "string") return message; + + return message + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/\"/g, """) + .replace(/\'/g, "'"); +} + +module.exports = escapeHtml;