@contrast/protect 1.53.1 → 1.54.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/package.json +15 -12
  2. package/lib/error-handlers/common-handler.test.js +0 -52
  3. package/lib/error-handlers/index.test.js +0 -32
  4. package/lib/error-handlers/init-domain.test.js +0 -22
  5. package/lib/error-handlers/install/express.test.js +0 -290
  6. package/lib/error-handlers/install/fastify.test.js +0 -130
  7. package/lib/error-handlers/install/hapi.test.js +0 -102
  8. package/lib/error-handlers/install/koa2.test.js +0 -83
  9. package/lib/error-handlers/install/restify.test.js +0 -57
  10. package/lib/get-source-context.test.js +0 -35
  11. package/lib/hardening/handlers.test.js +0 -89
  12. package/lib/hardening/index.test.js +0 -31
  13. package/lib/hardening/install/node-serialize0.test.js +0 -58
  14. package/lib/index.test.js +0 -53
  15. package/lib/input-analysis/handlers.test.js +0 -1604
  16. package/lib/input-analysis/index.test.js +0 -45
  17. package/lib/input-analysis/install/body-parser1.test.js +0 -134
  18. package/lib/input-analysis/install/busboy1.test.js +0 -81
  19. package/lib/input-analysis/install/cookie-parser1.test.js +0 -144
  20. package/lib/input-analysis/install/express.test.js +0 -241
  21. package/lib/input-analysis/install/fastify.test.js +0 -96
  22. package/lib/input-analysis/install/formidable1.test.js +0 -114
  23. package/lib/input-analysis/install/hapi.test.js +0 -292
  24. package/lib/input-analysis/install/http.test.js +0 -270
  25. package/lib/input-analysis/install/koa-body5.test.js +0 -92
  26. package/lib/input-analysis/install/koa-bodyparser4.test.js +0 -92
  27. package/lib/input-analysis/install/koa2.test.js +0 -259
  28. package/lib/input-analysis/install/multer1.test.js +0 -209
  29. package/lib/input-analysis/install/qs6.test.js +0 -79
  30. package/lib/input-analysis/install/restify.test.js +0 -98
  31. package/lib/input-analysis/install/universal-cookie4.test.js +0 -70
  32. package/lib/input-analysis/ip-analysis.test.js +0 -71
  33. package/lib/input-analysis/virtual-patches.test.js +0 -106
  34. package/lib/input-tracing/handlers/index.test.js +0 -1236
  35. package/lib/input-tracing/index.test.js +0 -62
  36. package/lib/input-tracing/install/child-process.test.js +0 -133
  37. package/lib/input-tracing/install/eval.test.js +0 -78
  38. package/lib/input-tracing/install/fs.test.js +0 -108
  39. package/lib/input-tracing/install/function.test.js +0 -81
  40. package/lib/input-tracing/install/http.test.js +0 -85
  41. package/lib/input-tracing/install/http2.test.js +0 -83
  42. package/lib/input-tracing/install/marsdb.test.js +0 -126
  43. package/lib/input-tracing/install/mongodb.test.js +0 -280
  44. package/lib/input-tracing/install/mssql.test.js +0 -81
  45. package/lib/input-tracing/install/mysql.test.js +0 -108
  46. package/lib/input-tracing/install/postgres.test.js +0 -117
  47. package/lib/input-tracing/install/sequelize.test.js +0 -78
  48. package/lib/input-tracing/install/spdy.test.js +0 -76
  49. package/lib/input-tracing/install/sqlite3.test.js +0 -88
  50. package/lib/input-tracing/install/vm.test.js +0 -176
  51. package/lib/make-response-blocker.test.js +0 -99
  52. package/lib/make-source-context.test.js +0 -219
  53. package/lib/policy.test.js +0 -446
  54. package/lib/semantic-analysis/handlers.test.js +0 -379
  55. package/lib/semantic-analysis/index.test.js +0 -38
  56. package/lib/semantic-analysis/install/libxmljs.test.js +0 -156
  57. package/lib/semantic-analysis/utils/xml-analysis.test.js +0 -156
  58. package/lib/throw-security-exception.test.js +0 -37
@@ -1,379 +0,0 @@
1
- 'use strict';
2
-
3
- const os = require('os');
4
- const { Rule } = require('@contrast/common');
5
- const { expect } = require('chai');
6
- const mocks = require('@contrast/test/mocks');
7
-
8
- describe('protect semantic-analysis handlers', function () {
9
- let core, handlers;
10
-
11
- // each test should be asserting this at least
12
- const TEST_DESCRIPTION = 'captures findings and sinkContext in result.exploitMetadata array';
13
-
14
- // for additional assertions that might happen in tests, add to description
15
- function makeTestDescription(blocks) {
16
- const addl = blocks ? ' and blocks when in BLOCK mode' : '';
17
- return `${TEST_DESCRIPTION}${addl}`;
18
- }
19
-
20
- function makeSourceContext(resultsList, ruleModes) {
21
- const semanticResultsMap = Object.create(null);
22
- if (resultsList) {
23
- for (const result of resultsList) {
24
- if (!semanticResultsMap[result.ruleId]) {
25
- semanticResultsMap[result.ruleId] = [];
26
- }
27
- semanticResultsMap[result.ruleId].push(result);
28
- }
29
- }
30
-
31
- return {
32
- policy: {
33
- [Rule.CMD_INJECTION_COMMAND_BACKDOORS]: 'monitor',
34
- [Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]: 'monitor',
35
- [Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]: 'monitor',
36
- [Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS]: 'monitor',
37
- ...(ruleModes || {}),
38
- },
39
- trackRequest: true,
40
- resultsMap: semanticResultsMap,
41
- };
42
- }
43
-
44
- beforeEach(function () {
45
- core = mocks.core();
46
- core.logger = mocks.logger();
47
- core.protect = mocks.protect();
48
- core.protect.throwSecurityException = require('../throw-security-exception');
49
-
50
- handlers = require('./handlers')(core);
51
- });
52
-
53
- describe('handleCmdInjectionSemanticDangerous()', function () {
54
- const sinkContextPositive = {
55
- name: 'child_process.execSync',
56
- value: 'ls; cat /etc/passwd',
57
- stack: [],
58
- };
59
- const sinkContextNegative = {
60
- name: 'child_process.execSync',
61
- value: 'foo',
62
- stack: []
63
- };
64
- const command = 'ls; cat /etc/passwd';
65
-
66
- [
67
- {
68
- blocks: false,
69
- sourceContext: makeSourceContext([]),
70
- expectedResults: [
71
- {
72
- mappedId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
73
- ruleId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
74
- value: sinkContextPositive.value,
75
- sinkContext: sinkContextPositive,
76
- exploitMetadata: [{ command }],
77
- blocked: false
78
- },
79
- {
80
- mappedId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
81
- ruleId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
82
- value: sinkContextPositive.value,
83
- sinkContext: sinkContextPositive,
84
- exploitMetadata: [{ command }],
85
- blocked: false
86
- },
87
- ]
88
- },
89
- {
90
- blocks: true,
91
- sourceContext: makeSourceContext(
92
- [], {
93
- [Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]: 'block'
94
- }
95
- ),
96
- expectedResults: [
97
- {
98
- mappedId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
99
- ruleId: Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS,
100
- value: sinkContextPositive.value,
101
- sinkContext: sinkContextPositive,
102
- exploitMetadata: [{ command }],
103
- blocked: true
104
- },
105
- ]
106
- },
107
- {
108
- blocks: false,
109
- sourceContext: makeSourceContext(
110
- [], {
111
- [Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS]: 'off'
112
- }
113
- ),
114
- expectedResults: undefined,
115
- }
116
- ].forEach(({ blocks, sourceContext, expectedResults }) => {
117
- it(makeTestDescription(blocks), function () {
118
- const testFn = () => {
119
- handlers.handleCmdInjectionSemanticDangerous(sourceContext, sinkContextPositive);
120
- handlers.handleCmdInjectionSemanticDangerous(sourceContext, sinkContextPositive);
121
- handlers.handleCmdInjectionSemanticDangerous(sourceContext, sinkContextNegative);
122
- };
123
-
124
- const test = expect(testFn);
125
- blocks ? test.to.throw('SecurityException') : test.not.to.throw();
126
-
127
- const cmdiSDPResults = sourceContext.resultsMap[Rule.CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS];
128
- expect(cmdiSDPResults).to.deep.equal(expectedResults);
129
- });
130
- });
131
- });
132
-
133
- describe('handleCmdInjectionSemanticChainedCommands()', function () {
134
- const sinkContextPositive = {
135
- name: 'child_process.execSync',
136
- value: 'test&whoami',
137
- stack: [],
138
- };
139
- const sinkContextNegative = {
140
- name: 'child_process.execSync',
141
- value: 'foo',
142
- stack: []
143
- };
144
- const command = 'test&whoami';
145
-
146
- [
147
- {
148
- blocks: false,
149
- sourceContext: makeSourceContext([]),
150
- expectedResults: [
151
- {
152
- mappedId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
153
- ruleId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
154
- value: sinkContextPositive.value,
155
- sinkContext: sinkContextPositive,
156
- exploitMetadata: [{ command }],
157
- blocked: false
158
- },
159
- {
160
- mappedId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
161
- ruleId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
162
- value: sinkContextPositive.value,
163
- sinkContext: sinkContextPositive,
164
- exploitMetadata: [{ command }],
165
- blocked: false
166
- },
167
- ]
168
- },
169
- {
170
- blocks: true,
171
- sourceContext: makeSourceContext(
172
- [], {
173
- [Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]: 'block'
174
- }
175
- ),
176
- expectedResults: [
177
- {
178
- mappedId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
179
- ruleId: Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS,
180
- value: sinkContextPositive.value,
181
- sinkContext: sinkContextPositive,
182
- exploitMetadata: [{ command }],
183
- blocked: true
184
- },
185
- ]
186
- },
187
- {
188
- blocks: false,
189
- sourceContext: makeSourceContext(
190
- [], {
191
- [Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS]: 'off'
192
- }
193
- ),
194
- expectedResults: undefined,
195
- }
196
- ].forEach(({ blocks, sourceContext, expectedResults }) => {
197
- it(makeTestDescription(blocks), function () {
198
- const testFn = () => {
199
- handlers.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContextPositive);
200
- handlers.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContextPositive);
201
- handlers.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContextNegative);
202
- };
203
-
204
- const test = expect(testFn);
205
- blocks ? test.to.throw('SecurityException') : test.not.to.throw();
206
-
207
-
208
- const cmdiSDPResults = sourceContext.resultsMap[Rule.CMD_INJECTION_SEMANTIC_CHAINED_COMMANDS];
209
- expect(cmdiSDPResults).to.deep.equal(expectedResults);
210
- });
211
- });
212
- });
213
-
214
- describe('handleCommandInjectionCommandBackdoors()', function () {
215
- const sinkContextPositive = {
216
- name: 'child_process.execSync',
217
- value: 'ls .',
218
- stack: [],
219
- };
220
- const sinkContextPositiveV2 = {
221
- name: 'child_process.execSync',
222
- value: '/bin/sh -c "cat /etc/passwd"',
223
- stack: [],
224
- };
225
- const sinkContextNegative = {
226
- name: 'child_process.execSync',
227
- value: 'f',
228
- stack: []
229
- };
230
- const command = 'ls .';
231
-
232
- [
233
- {
234
- blocks: false,
235
- sourceContext: makeSourceContext([]),
236
- expectedResults: [
237
- {
238
- sinkContext: sinkContextPositive,
239
- exploitMetadata: [{ command }],
240
- inputType: 'HEADER',
241
- key: 'malicious-header',
242
- path: [],
243
- blocked: false,
244
- value: 'ls .',
245
- mappedId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
246
- ruleId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
247
- },
248
- {
249
- sinkContext: sinkContextPositiveV2,
250
- exploitMetadata: [{ command: '/bin/sh -c "cat /etc/passwd"' }],
251
- inputType: 'JSON_VALUE',
252
- key: 'command',
253
- path: ['some', 'hidden'],
254
- blocked: false,
255
- value: '/bin/sh -c "cat /etc/passwd"',
256
- mappedId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
257
- ruleId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
258
- },
259
- ]
260
- },
261
- {
262
- blocks: true,
263
- sourceContext: makeSourceContext(
264
- [], {
265
- [Rule.CMD_INJECTION_COMMAND_BACKDOORS]: 'block'
266
- }
267
- ),
268
- expectedResults: [
269
- {
270
- sinkContext: sinkContextPositive,
271
- exploitMetadata: [{ command }],
272
- inputType: 'HEADER',
273
- key: 'malicious-header',
274
- path: [],
275
- blocked: true,
276
- value: 'ls .',
277
- mappedId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
278
- ruleId: Rule.CMD_INJECTION_COMMAND_BACKDOORS,
279
- },
280
- ]
281
- },
282
- {
283
- blocks: false,
284
- sourceContext: makeSourceContext(
285
- [], {
286
- [Rule.CMD_INJECTION_COMMAND_BACKDOORS]: 'off'
287
- }
288
- ),
289
- expectedResults: undefined,
290
- }
291
- ].forEach(({ blocks, sourceContext, expectedResults }) => {
292
- it(makeTestDescription(blocks), function () {
293
- sourceContext.reqData = {
294
- headers: ['some-other-header', 'and-its-value', 'malicious-header', 'ls .']
295
- };
296
- sourceContext.parsedBody = { some: { hidden: { command: '-c "cat /etc/passwd"' } } };
297
- const testFn = () => {
298
- handlers.handleCommandInjectionCommandBackdoors(sourceContext, sinkContextPositive);
299
- handlers.handleCommandInjectionCommandBackdoors(sourceContext, sinkContextPositiveV2);
300
- handlers.handleCommandInjectionCommandBackdoors(sourceContext, sinkContextNegative);
301
- };
302
-
303
- const test = expect(testFn);
304
- blocks ? test.to.throw('SecurityException') : test.not.to.throw();
305
-
306
-
307
- const cmdiSDPResults = sourceContext.resultsMap[Rule.CMD_INJECTION_COMMAND_BACKDOORS];
308
- expect(cmdiSDPResults).to.deep.equal(expectedResults);
309
- });
310
- });
311
- });
312
-
313
- describe('handlePathTraversalFileSecurityBypass()', function () {
314
- const sinkContextNegative = {
315
- name: 'fs.writeFile',
316
- value: 'f',
317
- stack: []
318
- };
319
- const sinkContexts = [{ name: 'fs.readFileSync', value: 'c:\textfile.txt::$DATA' }];
320
-
321
- if (os.platform() !== 'win32') {
322
- sinkContexts.push({ name: 'fs.readFile', value: '/etc/passwd' });
323
- }
324
-
325
- [
326
- {
327
- blocks: false,
328
- sourceContext: makeSourceContext([]),
329
- sinkContexts,
330
- expectedResults: sinkContexts.map((ctx) => ({
331
- sinkContext: ctx,
332
- exploitMetadata: [{ path: ctx.value }],
333
- blocked: false,
334
- mappedId: Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS,
335
- ruleId: Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS,
336
- value: ctx.value
337
- })),
338
- },
339
- {
340
- blocks: true,
341
- sourceContext: makeSourceContext([], {
342
- [Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS]: 'block',
343
- }),
344
- sinkContexts,
345
- expectedResults: [{
346
- sinkContext: sinkContexts[0],
347
- exploitMetadata: [{ path: sinkContexts[0].value }],
348
- blocked: true,
349
- mappedId: Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS,
350
- ruleId: Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS,
351
- value: sinkContexts[0].value
352
- }],
353
- },
354
- {
355
- blocks: false,
356
- sinkContexts,
357
- sourceContext: makeSourceContext([], {
358
- [Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS]: 'off',
359
- }),
360
- expectedResults: undefined,
361
- }
362
- ].forEach(({ blocks, sourceContext, sinkContexts, expectedResults }) => {
363
- it(makeTestDescription(blocks), function () {
364
- const testFn = () => {
365
- sinkContexts.forEach((sinkContext) => {
366
- handlers.handlePathTraversalFileSecurityBypass(sourceContext, sinkContext);
367
- });
368
- handlers.handlePathTraversalFileSecurityBypass(sourceContext, sinkContextNegative);
369
- };
370
-
371
- const test = expect(testFn);
372
- blocks ? test.to.throw('SecurityException') : test.not.to.throw();
373
-
374
- const results = sourceContext.resultsMap[Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS];
375
- expect(results).to.deep.equal(expectedResults);
376
- });
377
- });
378
- });
379
- });
@@ -1,38 +0,0 @@
1
- 'use strict';
2
-
3
- const { expect } = require('chai');
4
- const sinon = require('sinon');
5
- const proxyquire = require('proxyquire');
6
- const mocks = require('@contrast/test/mocks');
7
-
8
- describe('protect semantic-analysis', function () {
9
- let core, installStub, hooksMock;
10
-
11
- beforeEach(function () {
12
- core = mocks.core();
13
- core.protect = {};
14
- core.scopes = mocks.scopes();
15
- core.depHooks = mocks.depHooks();
16
- core.instrumentation = mocks.instrumentation();
17
- installStub = sinon.stub();
18
- hooksMock = (hookProp) => function (core) {
19
- if (core.protect.semanticAnalysis) {
20
- core.protect.semanticAnalysis[hookProp] = { install: installStub };
21
- } else {
22
- core.protect.semanticAnalysis = {
23
- [hookProp]: { install: installStub }
24
- };
25
- }
26
- };
27
- });
28
-
29
- it('calls the install() method of the required hooks', function () {
30
- const hooks = proxyquire('.', {
31
- './install/libxmljs': hooksMock('libxmljsInstrumentation')
32
- })(core);
33
-
34
- expect(installStub).not.to.have.been.called;
35
- hooks.install();
36
- expect(installStub).to.have.callCount(1);
37
- });
38
- });
@@ -1,156 +0,0 @@
1
- 'use strict';
2
-
3
- const sinon = require('sinon');
4
- const { expect } = require('chai');
5
- const patcher = require('@contrast/patcher');
6
- const mocks = require('@contrast/test/mocks');
7
- const SecurityException = require('../../security-exception');
8
-
9
- describe('protect semantic-analysis libxmljs', function () {
10
- const store = { protect: {} };
11
- let core, modules;
12
-
13
- beforeEach(function () {
14
- core = mocks.core();
15
- core.logger = mocks.logger();
16
- core.depHooks = mocks.depHooks();
17
- core.scopes = mocks.scopes();
18
- sinon.stub(core.scopes.sources, 'getStore').returns(store);
19
- core.patcher = patcher(core);
20
- core.protect = mocks.protect();
21
-
22
-
23
- modules = {
24
- 'libxmljs@0': {
25
- parseXml: sinon.stub().returns({})
26
- },
27
-
28
- 'libxmljs@1': {
29
- parseXml: sinon.stub().returns({})
30
- },
31
-
32
- 'libxmljs2': {
33
- parseXml: sinon.stub().returns({})
34
- },
35
- };
36
-
37
- core.depHooks.resolve
38
- .withArgs({ name: 'libxmljs', version: '>=1 <2' })
39
- .yields(modules['libxmljs@1'], { name: 'libxmljs', version: '1.0.9' });
40
- core.depHooks.resolve
41
- .withArgs({ name: 'libxmljs', version: '<1' })
42
- .yields(modules['libxmljs@0'], { name: 'libxmljs', version: '0.19.10' });
43
- core.depHooks.resolve
44
- .withArgs({ name: 'libxmljs2', version: '<1' })
45
- .yields(modules.libxmljs2, { name: 'libxmljs2', version: '0.32.0' });
46
-
47
- require('../../get-source-context')(core);
48
- require('./libxmljs')(core).install();
49
- });
50
-
51
- ['libxmljs@0', 'libxmljs@1', 'libxmljs2'].forEach((name) => {
52
- describe(name, function () {
53
- it('skips instrumentation if sourceContext is missing', function () {
54
- core.scopes.sources.getStore.returns(undefined);
55
-
56
- modules[name].parseXml('value');
57
-
58
- expect(core.protect.semanticAnalysis.handleXXE).not.to.have.been.called;
59
- });
60
-
61
- it('skips instrumentation if the value is not provided or not a string', function () {
62
- [
63
- undefined,
64
- null,
65
- () => ({}),
66
- {},
67
- 1,
68
- NaN,
69
- true
70
- ].forEach(value => {
71
- modules[name].parseXml(value);
72
- });
73
-
74
- expect(core.protect.semanticAnalysis.handleXXE).not.to.have.been.called;
75
- });
76
-
77
- it('skips instrumentation if noent is set to false', function () {
78
- modules[name].parseXml('string', { noent: false });
79
-
80
- expect(core.protect.semanticAnalysis.handleXXE).not.to.have.been.called;
81
- });
82
-
83
- if (name === 'libxmljs@1') {
84
- it('skips instrumentation if replaceEntities is set to false', function () {
85
- modules[name].parseXml('string', { replaceEntities: false });
86
-
87
- expect(core.protect.semanticAnalysis.handleXXE).not.to.have.been.called;
88
- });
89
- }
90
-
91
- it('calls handleXXE with sourceContext and sinkContext when noent: true', function () {
92
- const nameWithoutVersion = name.split('@')[0];
93
- const sinkContext = {
94
- name: `${nameWithoutVersion}:parseXml`,
95
- value: 'string1',
96
- stacktraceOpts: {
97
- constructorOpt: modules[name].parseXml,
98
- prependFrames: [sinon.match.func]
99
- }
100
- };
101
-
102
- modules[name].parseXml('string1', { noent: true });
103
-
104
- expect(core.protect.semanticAnalysis.handleXXE).to.have.been.calledWith(
105
- store.protect,
106
- sinkContext
107
- );
108
- });
109
-
110
- if (name === 'libxmljs@1') {
111
- it('calls handleXXE with sourceContext and sinkContext when replaceEntities: true', function () {
112
- const nameWithoutVersion = name.split('@')[0];
113
- const sinkContext = {
114
- name: `${nameWithoutVersion}:parseXml`,
115
- value: 'string1',
116
- stacktraceOpts: {
117
- constructorOpt: modules[name].parseXml,
118
- prependFrames: [sinon.match.func]
119
- }
120
- };
121
-
122
- modules[name].parseXml('string1', { replaceEntities: true });
123
-
124
- expect(core.protect.semanticAnalysis.handleXXE).to.have.been.calledWith(
125
- store.protect,
126
- sinkContext
127
- );
128
- });
129
- }
130
-
131
- it('logs an error when handleXXE throws an unknown error', function () {
132
- const nameWithoutVersion = name.split('@')[0];
133
- const err = new Error('unknown!');
134
- core.protect.semanticAnalysis.handleXXE.throws(err);
135
-
136
- expect(() =>
137
- modules[name].parseXml('string1', { noent: true })
138
- ).not.to.throw();
139
-
140
- expect(core.logger.error).to.have.been.calledWith(
141
- { err, funcKey: `protect-semantic-analysis:${nameWithoutVersion}:parseXml` },
142
- 'Unexpected error during semantic analysis'
143
- );
144
- });
145
-
146
- it('throws a SecurityException when handleXXE throws one', function () {
147
- const err = SecurityException.create();
148
- core.protect.semanticAnalysis.handleXXE.throws(err);
149
-
150
- expect(() =>
151
- modules[name].parseXml('string1', { noent: true })
152
- ).to.throw(err);
153
- });
154
- });
155
- });
156
- });