From 2fa5232a689e7ce604fe364e1a05356a20d996ff Mon Sep 17 00:00:00 2001 From: Alex Brasetvik Date: Thu, 17 Oct 2019 00:33:20 +0200 Subject: [PATCH] Sanitize sourceURL so it cannot affect evaled code --- lodash.js | 14 ++++++-------- test/test.js | 12 ++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lodash.js b/lodash.js index d8b959a17f0..747f05c41d5 100644 --- a/lodash.js +++ b/lodash.js @@ -14819,11 +14819,11 @@ // Use a sourceURL for easier debugging. // The sourceURL gets injected into the source that's eval-ed, so be careful - // with lookup (in case of e.g. prototype pollution), and strip newlines if any. - // A newline wouldn't be a valid sourceURL anyway, and it'd enable code injection. - var sourceURL = '//# sourceURL=' + - (hasOwnProperty.call(options, 'sourceURL') - ? (options.sourceURL + '').replace(/[\r\n]/g, ' ') + // to normalize all kinds of whitespace, so e.g. newlines (and unicode versions of it) can't sneak in + // and escape the comment, thus injecting code that gets evaled. + var sourceURL = '//# sourceURL=' + ( + options.sourceURL + ? (options.sourceURL + '').replace(/\s/g, ' ') : ('lodash.templateSources[' + (++templateCounter) + ']') ) + '\n'; @@ -14856,9 +14856,7 @@ // If `variable` is not specified wrap a with-statement around the generated // code to add the data object to the top of the scope chain. - // Like with sourceURL, we take care to not check the option's prototype, - // as this configuration is a code injection vector. - var variable = hasOwnProperty.call(options, 'variable') && options.variable; + var variable = options.variable; if (!variable) { source = 'with (obj) {\n' + source + '\n}\n'; } diff --git a/test/test.js b/test/test.js index fed616b2805..350880a80f3 100644 --- a/test/test.js +++ b/test/test.js @@ -22625,6 +22625,18 @@ assert.deepEqual(actual, expected); }); + QUnit.test('should not let a sourceURL inject code', function(assert) { + assert.expect(1); + + var actual, + expected = 'no error'; + try { + actual = _.template(expected, {'sourceURL': '\u2028\u2029\n!this would err if it was executed!'})(); + } catch (e) {} + + assert.equal(actual, expected); + }); + QUnit.test('should work as an iteratee for methods like `_.map`', function(assert) { assert.expect(1);