Package: release.debian.org Severity: normal Tags: buster User: [email protected] Usertags: pu X-Debbugs-Cc: [email protected]
[ Reason ] node-handlebars is vulnerable to Arbitrary Code Execution and Remote Code Execution (CVE-2019-20920 and CVE-2021-23369) [ Impact ] Medium vulnerabilities [ Tests ] Sadly there are no test launched in Buster even if upstream added some checks [ Risks ] Medium risk, upstream patches were applied without changes [ Checklist ] [X] *all* changes are documented in the d/changelog [X] I reviewed all changes and I approve them [X] attach debdiff against the package in (old)stable [X] the issue is verified as fixed in unstable [ Changes ] More checks for given arguments Cheers, Yadd
diff --git a/debian/changelog b/debian/changelog index e49c409..e55d497 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +node-handlebars (3:4.1.0-1+deb10u3) buster; urgency=medium + + * Team upload + * Fix arbitrary code execution (Closes: CVE-2019-20920) + * Fix remote code execution (Closes: CVE-2021-23369) + + -- Yadd <[email protected]> Fri, 16 Apr 2021 10:31:24 +0200 + node-handlebars (3:4.1.0-1+deb10u2) buster; urgency=medium * Fix regression introduced in 3:4.1.0-1+deb10u1 diff --git a/debian/patches/CVE-2019-20920.patch b/debian/patches/CVE-2019-20920.patch new file mode 100644 index 0000000..54e3bd3 --- /dev/null +++ b/debian/patches/CVE-2019-20920.patch @@ -0,0 +1,114 @@ +Description: fix for CVE-2019-20920 +Author: Nils Knappmeier <[email protected]> +Origin: upstream, https://github.com/handlebars-lang/handlebars.js/commit/1988878 +Bug: https://snyk.io/vuln/SNYK-JS-HANDLEBARS-534478 +Forwarded: not-needed +Reviewed-By: Xavier Guimard <[email protected]> +Last-Update: 2020-10-12 + +--- a/lib/handlebars/compiler/compiler.js ++++ b/lib/handlebars/compiler/compiler.js +@@ -56,7 +56,7 @@ + + // These changes will propagate to the other compiler components + let knownHelpers = options.knownHelpers; +- options.knownHelpers = { ++ options.knownHelpers = extend(Object.create(null), { + 'helperMissing': true, + 'blockHelperMissing': true, + 'each': true, +@@ -65,15 +65,7 @@ + 'with': true, + 'log': true, + 'lookup': true +- }; +- if (knownHelpers) { +- // the next line should use "Object.keys", but the code has been like this a long time and changing it, might +- // cause backwards-compatibility issues... It's an old library... +- // eslint-disable-next-line guard-for-in +- for (let name in knownHelpers) { +- this.options.knownHelpers[name] = knownHelpers[name]; +- } +- } ++ }, options.knownHelpers); + + return this.accept(program); + }, +--- a/lib/handlebars/compiler/javascript-compiler.js ++++ b/lib/handlebars/compiler/javascript-compiler.js +@@ -2,6 +2,7 @@ + import Exception from '../exception'; + import {isArray} from '../utils'; + import CodeGen from './code-gen'; ++import {dangerousPropertyRegex} from '../helpers/lookup'; + + function Literal(value) { + this.value = value; +@@ -13,8 +14,9 @@ + // 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 (dangerousPropertyRegex.test(name)) { ++ const isEnumerable = [ this.aliasable('container.propertyIsEnumerable'), '.call(', parent, ',', JSON.stringify(name), ')']; ++ return ['(', isEnumerable, '?', _actualLookup(), ' : undefined)']; + } + if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { + return [parent, '.', name]; +--- a/lib/handlebars/helpers/lookup.js ++++ b/lib/handlebars/helpers/lookup.js +@@ -1,5 +1,13 @@ ++export const dangerousPropertyRegex = /^(constructor|__defineGetter__|__defineSetter__|__lookupGetter__|__proto__)$/; ++ + export default function(instance) { + instance.registerHelper('lookup', function(obj, field) { +- return obj && obj[field]; ++ if (!obj) { ++ return obj; ++ } ++ if (dangerousPropertyRegex.test(String(field)) && !obj.propertyIsEnumerable(field)) { ++ return undefined; ++ } ++ return obj[field]; + }); + } +--- a/spec/security.js ++++ b/spec/security.js +@@ -21,6 +21,36 @@ + }); + }); + ++ describe('GH-1563', function() { ++ it('should not allow to access constructor after overriding via __defineGetter__', function() { ++ if (({}).__defineGetter__ == null || ({}).__lookupGetter__ == null) { ++ return this.skip(); // Browser does not support this exploit anyway ++ } ++ expectTemplate('{{__defineGetter__ "undefined" valueOf }}' + ++ '{{#with __lookupGetter__ }}' + ++ '{{__defineGetter__ "propertyIsEnumerable" (this.bind (this.bind 1)) }}' + ++ '{{constructor.name}}' + ++ '{{/with}}') ++ .withInput({}) ++ .toThrow(/Missing helper: "__defineGetter__"/); ++ }); ++ }); ++ ++ describe('GH-1595', function() { ++ it('properties, that are required to be enumerable', function() { ++ expectTemplate('{{constructor}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{__defineGetter__}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{__defineSetter__}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{__lookupGetter__}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{__proto__}}').withInput({}).toCompileTo(''); ++ ++ expectTemplate('{{lookup "constructor"}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{lookup "__defineGetter__"}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{lookup "__defineSetter__"}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{lookup "__lookupGetter__"}}').withInput({}).toCompileTo(''); ++ expectTemplate('{{lookup "__proto__"}}').withInput({}).toCompileTo(''); ++ }); ++ }); + describe('GH-xxxx: Prevent explicit call of helperMissing-helpers', function() { + if (!Handlebars.compile) { + return; diff --git a/debian/patches/CVE-2021-23369.patch b/debian/patches/CVE-2021-23369.patch new file mode 100644 index 0000000..81ca9be --- /dev/null +++ b/debian/patches/CVE-2021-23369.patch @@ -0,0 +1,38 @@ +Description: fix Remote Code Execution (RCE) + when selecting certain compiling options to compile templates coming from an + untrusted source. +Author: Nils Knappmeier <[email protected]> +Origin: upstream, https://github.com/handlebars-lang/handlebars.js/commit/b6d3de71 + https://github.com/handlebars-lang/handlebars.js/commit/f0589701 +Bug: https://snyk.io/vuln/SNYK-JS-HANDLEBARS-1056767 +Forwarded: not-needed +Reviewed-By: Yadd <[email protected]> +Last-Update: 2021-04-16 + +--- a/lib/handlebars/compiler/javascript-compiler.js ++++ b/lib/handlebars/compiler/javascript-compiler.js +@@ -25,7 +25,12 @@ + } + }, + depthedLookup: function(name) { +- return [this.aliasable('container.lookup'), '(depths, "', name, '")']; ++ return [ ++ this.aliasable('container.lookup'), ++ '(depths, ', ++ JSON.stringify(name), ++ ')' ++ ]; + }, + + compilerInfo: function() { +--- a/lib/handlebars/runtime.js ++++ b/lib/handlebars/runtime.js +@@ -78,7 +78,7 @@ + if (!(name in obj)) { + throw new Exception('"' + name + '" not defined in ' + obj); + } +- return obj[name]; ++ return container.lookupProperty(obj, name); + }, + lookup: function(depths, name) { + const len = depths.length; diff --git a/debian/patches/series b/debian/patches/series index 7cf0804..da74c64 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,3 +2,5 @@ port-to-babel6-webpack3.patch skip-some-modules.patch use-system-jison.patch CVE-2019-19919.patch +CVE-2019-20920.patch +CVE-2021-23369.patch

