From 95d571f3fe801ff9ef63b1fb83dad5a0f7911ea4 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 | 8 +++----- test/test.js | 12 ++++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lodash.js b/lodash.js index cbf3b38487..c724b6b8fd 100644 --- a/lodash.js +++ b/lodash.js @@ -14821,11 +14821,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. + // 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=' + (hasOwnProperty.call(options, 'sourceURL') - ? (options.sourceURL + '').replace(/[\r\n]/g, ' ') + ? (options.sourceURL + '').replace(/\s/g, ' ') : ('lodash.templateSources[' + (++templateCounter) + ']') ) + '\n'; @@ -14858,8 +14858,6 @@ // 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; if (!variable) { source = 'with (obj) {\n' + source + '\n}\n'; diff --git a/test/test.js b/test/test.js index 2bfb54669d..e9507a304a 100644 --- a/test/test.js +++ b/test/test.js @@ -22641,6 +22641,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);