diff --git a/lodash.js b/lodash.js index 1fd7116f42..01cc2e6e4c 100644 --- a/lodash.js +++ b/lodash.js @@ -165,6 +165,16 @@ /** Used to match words composed of alphanumeric characters. */ var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + /** + * used to validate the template variable. Forbids chars changing the argument definition to inject things: + * - parenthesis and comma (as that controls the argument list) + * - = sign (default value) + * - curly braces and square braces, to forbid destructuring in the argument name + * - / (start of a comment hiding some parts) + * - whitespaces + */ + var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/ + /** Used to match backslashes in property paths. */ var reEscapeChar = /\\(\\)?/g; @@ -14865,6 +14875,8 @@ var variable = hasOwnProperty.call(options, 'variable') && options.variable; if (!variable) { source = 'with (obj) {\n' + source + '\n}\n'; + } else if (reForbiddenIdentifierChars.test(variable)) { + throw new Error('Invalid variable name. It must be a valid EcmaScript identifier.') } // Cleanup code by stripping empty strings. source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source) diff --git a/test/test.js b/test/test.js index 605f80cfc0..a976e9b440 100644 --- a/test/test.js +++ b/test/test.js @@ -22296,6 +22296,14 @@ } }); + QUnit.test('should forbid code injection through the "variable" options', function(assert) { + assert.expect(1); + + assert.throws(function () { + _.template('', { 'variable': '){console.log(process.env)}; with(obj' }); + }); + }); + QUnit.test('should support custom delimiters', function(assert) { assert.expect(2);