From 38ee9d751c509eb9c5f963a6de784f3c436e9a86 Mon Sep 17 00:00:00 2001 From: Chen Yangjian <252317+dotnil@users.noreply.github.com> Date: Thu, 24 Jan 2019 11:21:09 +0800 Subject: [PATCH] fix regex in utils.stackTraceFilter to prevent ReDoS #3416 if the stack trace begins with a large error message (>= 20k charactors), and user leaves `--full-trace` disabled, `utils.stackTraceFilter()` takes ages to finish. Large error messages is quite possible when user makes containment assertions such as `expect(content).to.contain(word)`. --- lib/utils.js | 4 +-- test/unit/runner.spec.js | 56 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 8dc41bc924..bf50ee8ee9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -671,8 +671,6 @@ exports.stackTraceFilter = function() { function isMochaInternal(line) { return ( ~line.indexOf('node_modules' + slash + 'mocha' + slash) || - ~line.indexOf('node_modules' + slash + 'mocha.js') || - ~line.indexOf('bower_components' + slash + 'mocha.js') || ~line.indexOf(slash + 'mocha.js') ); } @@ -701,7 +699,7 @@ exports.stackTraceFilter = function() { } // Clean up cwd(absolute) - if (/\(?.+:\d+:\d+\)?$/.test(line)) { + if (/:\d+:\d+\)?$/.test(line)) { line = line.replace('(' + cwd, '('); } diff --git a/test/unit/runner.spec.js b/test/unit/runner.spec.js index 7ae4984117..78d1286b70 100644 --- a/test/unit/runner.spec.js +++ b/test/unit/runner.spec.js @@ -496,6 +496,62 @@ describe('Runner', function() { runner.failHook(hook, err); }); }); + + describe('hugeStackTrace', function() { + beforeEach(function() { + if (path.sep !== '/') { + this.skip(); + } + }); + + it('should not hang if the error message is ridiculously long single line', function(done) { + var hook = new Hook(); + hook.parent = suite; + var data = []; + // mock a long message + for (var i = 0; i < 10000; i++) data[i] = {a: 1}; + var message = JSON.stringify(data); + var err = new Error(); + // Fake stack-trace + err.stack = [message].concat(stack).join('\n'); + + runner.on('fail', function(hook, err) { + expect( + err.stack + .split('\n') + .slice(1) + .join('\n'), + 'to be', + stack.slice(0, 3).join('\n') + ); + done(); + }); + runner.failHook(hook, err); + }); + + it('should not hang if error message is ridiculously long multiple lines either', function(done) { + var hook = new Hook(); + hook.parent = suite; + var fpath = require('path').join(__dirname, '../../mocha.js'); + var message = require('fs').readFileSync(fpath, 'utf8'); + var err = new Error(); + // Fake stack-trace + err.stack = [message].concat(stack).join('\n'); + + runner.on('fail', function(hook, err) { + expect( + err.stack + .split('\n') + .slice(-3) + .join('\n'), + 'to be', + stack.slice(0, 3).join('\n') + ); + done(); + }); + runner.failHook(hook, err); + }); + }); }); describe('abort', function() {