From 213c0bbe3c4bd83a534d67384e5afa0000347ff6 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Thu, 26 Sep 2019 23:55:14 +0200 Subject: [PATCH 1/3] Use Object.prototype.propertyIsEnumerable to check for constructors - context.propertyIsEnumerable can be replaced via __definedGetter__ - This is a fix specific to counter a known RCE exploit. Other fixes will follow. closes #1563 --- .../compiler/javascript-compiler.js | 36 +++++++++++-------- spec/security.js | 12 ++++++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 1b9b2318d..3491aad8e 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -14,12 +14,20 @@ JavaScriptCompiler.prototype = { // alternative compiled forms for name lookup and buffering semantics nameLookup: function(parent, name/* , type*/) { if (name === 'constructor') { - return ['(', parent, '.propertyIsEnumerable(\'constructor\') ? ', parent, '.constructor : undefined', ')']; + return ['(', _isEnumerable(), '?', _actualLookup(), ' : undefined)']; } - if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return [parent, '.', name]; - } else { - return [parent, '[', JSON.stringify(name), ']']; + return _actualLookup(); + + function _isEnumerable() { + return `Object.prototype.propertyIsEnumerable.call(${parent},'constructor')`; + } + + function _actualLookup() { + if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { + return [parent, '.', name]; + } else { + return [parent, '[', JSON.stringify(name), ']']; + } } }, depthedLookup: function(name) { @@ -339,9 +347,9 @@ JavaScriptCompiler.prototype = { params.splice(1, 0, current); this.pushSource([ - 'if (!', this.lastHelper, ') { ', - current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), - '}']); + 'if (!', this.lastHelper, ') { ', + current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), + '}']); }, // [appendContent] @@ -686,16 +694,16 @@ JavaScriptCompiler.prototype = { if (!this.options.strict) { lookup[0] = '(helper = '; lookup.push( - ' != null ? helper : ', - this.aliasable('container.hooks.helperMissing') + ' != null ? helper : ', + this.aliasable('container.hooks.helperMissing') ); } this.push([ - '(', lookup, - (helper.paramsInit ? ['),(', helper.paramsInit] : []), '),', - '(typeof helper === ', this.aliasable('"function"'), ' ? ', - this.source.functionCall('helper', 'call', helper.callParams), ' : helper))' + '(', lookup, + (helper.paramsInit ? ['),(', helper.paramsInit] : []), '),', + '(typeof helper === ', this.aliasable('"function"'), ' ? ', + this.source.functionCall('helper', 'call', helper.callParams), ' : helper))' ]); }, diff --git a/spec/security.js b/spec/security.js index 4c092b1c0..418541f67 100644 --- a/spec/security.js +++ b/spec/security.js @@ -33,7 +33,7 @@ describe('security issues', function() { }); }); - describe('GH-xxxx: Prevent explicit call of helperMissing-helpers', function() { + describe('GH-1558: Prevent explicit call of helperMissing-helpers', function() { if (!Handlebars.compile) { return; } @@ -88,4 +88,14 @@ describe('security issues', function() { }); }); }); + + describe('GH-1563', function() { + it('should not allow to access constructor after overriding via __defineGetter__', function() { + shouldCompileTo('{{__defineGetter__ "undefined" valueOf }}' + + '{{#with __lookupGetter__ }}' + + '{{__defineGetter__ "propertyIsEnumerable" (this.bind (this.bind 1)) }}' + + '{{constructor.name}}' + + '{{/with}}', {}, ''); + }); + }); }); From c5cbeac039de4a05113dbe1f5e14f29175228c78 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Thu, 26 Sep 2019 23:58:13 +0200 Subject: [PATCH 2/3] Update release notes --- release-notes.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/release-notes.md b/release-notes.md index 45c90a162..9c21c53b0 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,15 @@ ## Development -[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.1...master) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.2...master) + +## v4.3.2 - September 26th, 2019 +- Use Object.prototype.propertyIsEnumerable to check for constructors - 213c0bb, #1563 + +Compatibility notes: +- There are no breaking changes + +[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.1...v4.3.2) ## v4.3.1 - September 25th, 2019 Fixes: From 2357140c68d17cb4f8ab74431e8737de6b4b39b5 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Thu, 26 Sep 2019 23:58:48 +0200 Subject: [PATCH 3/3] v4.3.2 --- components/bower.json | 2 +- components/handlebars.js.nuspec | 2 +- components/package.json | 2 +- lib/handlebars/base.js | 2 +- package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/bower.json b/components/bower.json index f26015d4c..3a6ce5344 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.3.1", + "version": "4.3.2", "main": "handlebars.js", "license": "MIT", "dependencies": {} diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec index 7f708a582..346e1174c 100644 --- a/components/handlebars.js.nuspec +++ b/components/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 4.3.1 + 4.3.2 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ diff --git a/components/package.json b/components/package.json index 09278636f..1842c2796 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.3.1", + "version": "4.3.2", "license": "MIT", "jspm": { "main": "handlebars", diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 631f5b0f8..205978f49 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -4,7 +4,7 @@ import {registerDefaultHelpers} from './helpers'; import {registerDefaultDecorators} from './decorators'; import logger from './logger'; -export const VERSION = '4.3.1'; +export const VERSION = '4.3.2'; export const COMPILER_REVISION = 8; export const LAST_COMPATIBLE_COMPILER_REVISION = 7; diff --git a/package.json b/package.json index f616e4879..1ae2c833e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "barename": "handlebars", - "version": "4.3.1", + "version": "4.3.2", "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration", "homepage": "http://www.handlebarsjs.com/", "keywords": [