diff options
author | Darius Jahandarie <djahandarie@gmail.com> | 2023-11-04 18:45:57 +0900 |
---|---|---|
committer | Darius Jahandarie <djahandarie@gmail.com> | 2023-11-04 18:45:57 +0900 |
commit | ef79eab44bfd000792c610b968b5ceefd41e76a0 (patch) | |
tree | 48b04f30f6248caedbd880801aa49402a9e8066a /dev/lib/handlebars/src/spec/index.security.test.ts | |
parent | 376151096431d4362e4baaacf0cef4a534e169f7 (diff) |
Modernize codebase
- Use ES modules
- Remove vendored libs and build them from npm using esbuild
- Switch from JSZip to zip.js
Diffstat (limited to 'dev/lib/handlebars/src/spec/index.security.test.ts')
-rw-r--r-- | dev/lib/handlebars/src/spec/index.security.test.ts | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/dev/lib/handlebars/src/spec/index.security.test.ts b/dev/lib/handlebars/src/spec/index.security.test.ts new file mode 100644 index 00000000..878a0931 --- /dev/null +++ b/dev/lib/handlebars/src/spec/index.security.test.ts @@ -0,0 +1,132 @@ +/* + * This file is forked from the handlebars project (https://github.com/handlebars-lang/handlebars.js), + * and may include modifications made by Elasticsearch B.V. + * Elasticsearch B.V. licenses this file to you under the MIT License. + * See `packages/kbn-handlebars/LICENSE` for more information. + */ + +import Handlebars from '../..'; +import { expectTemplate } from '../__jest__/test_bench'; + +describe('security issues', () => { + describe('GH-1495: Prevent Remote Code Execution via constructor', () => { + it('should not allow constructors to be accessed', () => { + expectTemplate('{{lookup (lookup this "constructor") "name"}}').withInput({}).toCompileTo(''); + expectTemplate('{{constructor.name}}').withInput({}).toCompileTo(''); + }); + + it('GH-1603: should not allow constructors to be accessed (lookup via toString)', () => { + expectTemplate('{{lookup (lookup this (list "constructor")) "name"}}') + .withInput({}) + .withHelper('list', function (element) { + return [element]; + }) + .toCompileTo(''); + }); + + it('should allow the "constructor" property to be accessed if it is an "ownProperty"', () => { + expectTemplate('{{constructor.name}}') + .withInput({ constructor: { name: 'here we go' } }) + .toCompileTo('here we go'); + + expectTemplate('{{lookup (lookup this "constructor") "name"}}') + .withInput({ constructor: { name: 'here we go' } }) + .toCompileTo('here we go'); + }); + + it('should allow the "constructor" property to be accessed if it is an "own property"', () => { + expectTemplate('{{lookup (lookup this "constructor") "name"}}') + .withInput({ constructor: { name: 'here we go' } }) + .toCompileTo('here we go'); + }); + }); + + describe('GH-1558: Prevent explicit call of helperMissing-helpers', () => { + describe('without the option "allowExplicitCallOfHelperMissing"', () => { + it('should throw an exception when calling "{{helperMissing}}" ', () => { + expectTemplate('{{helperMissing}}').toThrow(Error); + }); + + it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', () => { + expectTemplate('{{#helperMissing}}{{/helperMissing}}').toThrow(Error); + }); + + it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', () => { + const functionCalls = []; + expect(() => { + const template = Handlebars.compile('{{blockHelperMissing "abc" .}}'); + template({ + fn() { + functionCalls.push('called'); + }, + }); + }).toThrow(Error); + expect(functionCalls.length).toEqual(0); + }); + + it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', () => { + expectTemplate('{{#blockHelperMissing .}}{{/blockHelperMissing}}') + .withInput({ + fn() { + return 'functionInData'; + }, + }) + .toThrow(Error); + }); + }); + }); + + describe('GH-1563', () => { + it('should not allow to access constructor after overriding via __defineGetter__', () => { + // @ts-expect-error + if ({}.__defineGetter__ == null || {}.__lookupGetter__ == null) { + return; // 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: dangerous properties', () => { + const templates = [ + '{{constructor}}', + '{{__defineGetter__}}', + '{{__defineSetter__}}', + '{{__lookupGetter__}}', + '{{__proto__}}', + '{{lookup this "constructor"}}', + '{{lookup this "__defineGetter__"}}', + '{{lookup this "__defineSetter__"}}', + '{{lookup this "__lookupGetter__"}}', + '{{lookup this "__proto__"}}', + ]; + + templates.forEach((template) => { + describe('access should be denied to ' + template, () => { + it('by default', () => { + expectTemplate(template).withInput({}).toCompileTo(''); + }); + }); + }); + }); + + describe('escapes template variables', () => { + it('in default mode', () => { + expectTemplate("{{'a\\b'}}").withCompileOptions().withInput({ 'a\\b': 'c' }).toCompileTo('c'); + }); + + it('in strict mode', () => { + expectTemplate("{{'a\\b'}}") + .withCompileOptions({ strict: true }) + .withInput({ 'a\\b': 'c' }) + .toCompileTo('c'); + }); + }); +}); |