forked from handlebars-lang/handlebars.js
/
security.js
128 lines (112 loc) · 4.41 KB
/
security.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
describe('security issues', function() {
describe('GH-1495: Prevent Remote Code Execution via constructor', function() {
checkPropertyAccess({});
describe('in compat-mode', function() {
checkPropertyAccess({ compat: true });
});
describe('in strict-mode', function() {
checkPropertyAccess({ strict: true });
});
function checkPropertyAccess(compileOptions) {
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
expectTemplate('{{constructor.name}}')
.withCompileOptions(compileOptions)
.withInput({'constructor': {
'name': 'here we go'
}})
.toCompileTo('here we go');
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
.withCompileOptions(compileOptions)
.withInput({'constructor': {
'name': 'here we go'
}})
.toCompileTo('here we go');
});
it('should allow prototype properties that are not constructors', function() {
function TestClass() {
}
Object.defineProperty(TestClass.prototype, 'abc', {
get: function() {
return 'xyz';
}
});
expectTemplate('{{#with this}}{{this.abc}}{{/with}}')
.withCompileOptions(compileOptions)
.withInput(new TestClass())
.toCompileTo('xyz');
expectTemplate('{{#with this}}{{lookup this "abc"}}{{/with}}')
.withCompileOptions(compileOptions)
.withInput(new TestClass())
.toCompileTo('xyz');
});
it('should not allow constructors to be accessed', function() {
expectTemplate('{{lookup (lookup this "constructor") "name"}}')
.withCompileOptions(compileOptions)
.withInput({})
.toCompileTo('');
if (compileOptions.strict) {
expectTemplate('{{constructor.name}}')
.withCompileOptions(compileOptions)
.withInput({})
.toThrow(TypeError);
} else {
expectTemplate('{{constructor.name}}')
.withCompileOptions(compileOptions)
.withInput({})
.toCompileTo('');
}
});
it('should not allow __proto__ to be accessed', function() {
expectTemplate('{{lookup (lookup this "__proto__") "name"}}')
.withCompileOptions(compileOptions)
.withInput({})
.toCompileTo('');
if (compileOptions.strict) {
expectTemplate('{{__proto__.name}}')
.withCompileOptions(compileOptions)
.withInput({})
.toThrow(TypeError);
} else {
expectTemplate('{{__proto__.name}}')
.withCompileOptions(compileOptions)
.withInput({})
.toCompileTo('');
}
});
}
});
describe('GH-1595', function() {
it('properties, that are required to be enumerable', function() {
shouldCompileTo('{{constructor.name}}', {}, '');
shouldCompileTo('{{__defineGetter__.name}}', {}, '');
shouldCompileTo('{{__defineSetter__.name}}', {}, '');
shouldCompileTo('{{__lookupGetter__.name}}', {}, '');
shouldCompileTo('{{__proto__.__defineGetter__.name}}', {}, '');
shouldCompileTo('{{lookup this "constructor"}}', {}, '');
shouldCompileTo('{{lookup this "__defineGetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__defineSetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__lookupGetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__proto__"}}', {}, '');
});
});
describe('escapes template variables', function() {
it('in compat mode', function() {
expectTemplate("{{'a\\b'}}")
.withCompileOptions({ compat: true })
.withInput({ 'a\\b': 'c' })
.toCompileTo('c');
});
it('in default mode', function() {
expectTemplate("{{'a\\b'}}")
.withCompileOptions()
.withInput({ 'a\\b': 'c' })
.toCompileTo('c');
});
it('in default mode', function() {
expectTemplate("{{'a\\b'}}")
.withCompileOptions({ strict: true })
.withInput({ 'a\\b': 'c' })
.toCompileTo('c');
});
});
});