From 49264e0037e313a0a3e033450b5c184112516d8f Mon Sep 17 00:00:00 2001 From: mde Date: Thu, 1 Dec 2016 16:21:47 -0800 Subject: [PATCH] Blacklist a few other unsafe opts from passing in data obj --- lib/ejs.js | 14 +++++++++----- test/ejs.js | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/ejs.js b/lib/ejs.js index 98e5991c..04b9bcb6 100644 --- a/lib/ejs.js +++ b/lib/ejs.js @@ -56,6 +56,12 @@ var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)'; var _OPTS = [ 'cache', 'filename', 'delimiter', 'scope', 'context', 'debug', 'compileDebug', 'client', '_with', 'root', 'rmWhitespace', 'strict', 'localsName']; +var _OPTS_IN_DATA_BLACKLIST = { + cache: true, + filename: true, + root: true, + localsName: true + }; var _BOM = /^\uFEFF/; /** @@ -268,11 +274,9 @@ function rethrow(err, str, filename, lineno){ function cpOptsInData(data, opts) { _OPTS.forEach(function (p) { if (typeof data[p] != 'undefined') { - // Disallow setting the root opt for includes via a passed data obj - // Unsanitized, parameterized use of `render` could allow the - // include directory to be reset, opening up the possibility of - // remote code execution - if (p == 'root') { + // Disallow passing potentially dangerous opts in the data + // These opts should not be settable via a `render` call + if (_OPTS_IN_DATA_BLACKLIST[p]) { return; } opts[p] = data[p]; diff --git a/test/ejs.js b/test/ejs.js index c2bb87a7..b8cb4c9d 100644 --- a/test/ejs.js +++ b/test/ejs.js @@ -168,6 +168,21 @@ suite('ejs.compile(str, options)', function () { }); +/* Old API -- remove when this shim goes away */ +suite('ejs.render(str, dataAndOpts)', function () { + test('render the template with data/opts passed together', function () { + assert.equal(ejs.render('

', {foo: 'yay', delimiter: '?'}), + '

yay

'); + }); + + test('disallow unsafe opts passed along in data', function () { + assert.equal(ejs.render('

', + // localsName should not get reset because it's blacklisted + {_with: false, foo: 'yay', delimiter: '?', localsName: '_'}), + '

yay

'); + }); +}); + suite('ejs.render(str, data, opts)', function () { test('render the template', function () { assert.equal(ejs.render('

yay

'), '

yay

'); @@ -753,7 +768,6 @@ suite('include()', function () { var viewsPath = path.join(__dirname, 'fixtures'); assert.equal(ejs.render(fixture('include-root.ejs'), {pets: users}, {filename: file, delimiter: '@',root:viewsPath}), fixture('include.html')); - }); test('work when nested', function () { @@ -918,7 +932,7 @@ suite('preprocessor include', function () { var template = fixture('include_preprocessor_line_slurp.ejs'); var expected = fixture('include_preprocessor_line_slurp.html'); var options = {rmWhitespace: true, filename: file}; - assert.equal(ejs.render(template, options), + assert.equal(ejs.render(template, {}, options), expected); });