diff options
| author | Darius Jahandarie <djahandarie@gmail.com> | 2023-11-09 13:30:31 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-09 13:30:31 +0000 | 
| commit | 5c5a167b4792af379cdacf633513cebf20728cd2 (patch) | |
| tree | 5b6be3620a557d0b9177047003f6d742d9d2a32d /dev/lib/handlebars/src/spec/index.security.test.ts | |
| parent | b64f51c3b13a46af4dd7f1e43048ac19c781ca7b (diff) | |
| parent | 0f4d36938fd0d844f548aa5a7f7e7842df8dfb41 (diff) | |
Merge pull request #307 from themoeway/modernize
Modernize codebase
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'); +    }); +  }); +}); |