Prevent command injection through _.template's variable option

Closes #5085.
This commit is contained in:
Christophe Coevoet
2021-02-17 12:33:19 +01:00
committed by Benjamin Tan
parent ded9bc6658
commit 3469357cff
2 changed files with 28 additions and 1 deletions

View File

@@ -19,7 +19,8 @@
/** Error message constants. */
var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
FUNC_ERROR_TEXT = 'Expected a function';
FUNC_ERROR_TEXT = 'Expected a function',
INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`';
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
@@ -165,6 +166,18 @@
/** Used to match words composed of alphanumeric characters. */
var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
/**
* Used to validate the `validate` option in `_.template` variable.
*
* Forbids characters which could potentially change the meaning of the function argument definition:
* - "()," (modification of function parameters)
* - "=" (default value)
* - "[]{}" (destructuring of function parameters)
* - "/" (beginning of a comment)
* - whitespace
*/
var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/;
/** Used to match backslashes in property paths. */
var reEscapeChar = /\\(\\)?/g;
@@ -14866,6 +14879,12 @@
if (!variable) {
source = 'with (obj) {\n' + source + '\n}\n';
}
// Throw an error if a forbidden character was found in `variable`, to prevent
// potential command injection attacks.
else if (reForbiddenIdentifierChars.test(variable)) {
throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT);
}
// Cleanup code by stripping empty strings.
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
.replace(reEmptyStringMiddle, '$1')

View File

@@ -22296,6 +22296,14 @@
}
});
QUnit.test('should forbid code injection through the "variable" options', function(assert) {
assert.expect(1);
assert.raises(function () {
_.template('', { 'variable': '){console.log(process.env)}; with(obj' });
});
});
QUnit.test('should support custom delimiters', function(assert) {
assert.expect(2);