@@ -10,11 +10,26 @@ import reInterpolate from './_reInterpolate.js';
1010import templateSettings from './templateSettings.js' ;
1111import toString from './toString.js' ;
1212
13+ /** Error message constants. */
14+ var INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`' ;
15+
1316/** Used to match empty string literals in compiled template source. */
1417var reEmptyStringLeading = / \b _ _ p \+ = ' ' ; / g,
1518 reEmptyStringMiddle = / \b ( _ _ p \+ = ) ' ' \+ / g,
1619 reEmptyStringTrailing = / ( _ _ e \( .* ?\) | \b _ _ t \) ) \+ \n ' ' ; / g;
1720
21+ /**
22+ * Used to validate the `validate` option in `_.template` variable.
23+ *
24+ * Forbids characters which could potentially change the meaning of the function argument definition:
25+ * - "()," (modification of function parameters)
26+ * - "=" (default value)
27+ * - "[]{}" (destructuring of function parameters)
28+ * - "/" (beginning of a comment)
29+ * - whitespace
30+ */
31+ var reForbiddenIdentifierChars = / [ ( ) = , { } \[ \] \/ \s ] / ;
32+
1833/**
1934 * Used to match
2035 * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
@@ -210,6 +225,12 @@ function template(string, options, guard) {
210225 if ( ! variable ) {
211226 source = 'with (obj) {\n' + source + '\n}\n' ;
212227 }
228+ // Throw an error if a forbidden character was found in `variable`, to prevent
229+ // potential command injection attacks.
230+ else if ( reForbiddenIdentifierChars . test ( variable ) ) {
231+ throw new Error ( INVALID_TEMPL_VAR_ERROR_TEXT ) ;
232+ }
233+
213234 // Cleanup code by stripping empty strings.
214235 source = ( isEvaluating ? source . replace ( reEmptyStringLeading , '' ) : source )
215236 . replace ( reEmptyStringMiddle , '$1' )
0 commit comments