From 42841c41a49bf9dc0c9c2eebefd54f35b38d9544 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Wed, 30 Jan 2019 22:21:44 +0100 Subject: [PATCH] fix: disallow access to the constructor in templates to prevent RCE This commit fixes a Remote Code Execution (RCE) reported by npm-security. Access to non-enumerable "constructor"-properties is now prohibited by the compiled template-code, because this the first step on the way to creating and execution arbitrary JavaScript code. The vulnerability affects systems where an attacker is allowed to inject templates into the Handlebars setup. Further details of the attack may be disclosed by npm-security. Closes #1267 Closes #1495 --- .../compiler/javascript-compiler.js | 3 +++ spec/security.js | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 spec/security.js diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 471144dd3..ff98ad9e4 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -13,6 +13,9 @@ JavaScriptCompiler.prototype = { // PUBLIC API: You can override these methods in a subclass to provide // alternative compiled forms for name lookup and buffering semantics nameLookup: function(parent, name/* , type*/) { + if (name === 'constructor') { + return ['(', parent, '.propertyIsEnumerable(\'constructor\') ? ', parent, '.constructor : undefined', ')']; + } if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { return [parent, '.', name]; } else { diff --git a/spec/security.js b/spec/security.js new file mode 100644 index 000000000..45b96c34b --- /dev/null +++ b/spec/security.js @@ -0,0 +1,23 @@ +describe('security issues', function() { + describe('GH-1495: Prevent Remote Code Execution via constructor', function() { + it('should not allow constructors to be accessed', function() { + shouldCompileTo('{{constructor.name}}', {}, ''); + }); + + it('should allow the "constructor" property to be accessed if it is enumerable', function() { + shouldCompileTo('{{constructor.name}}', {'constructor': { + 'name': 'here we go' + }}, 'here we go'); + }); + + it('should allow prototype properties that are not constructors', function() { + class TestClass { + get abc() { + return 'xyz'; + } + } + shouldCompileTo('{{#with this as |obj|}}{{obj.abc}}{{/with}}', + new TestClass(), 'xyz'); + }); + }); +});