@contrast/protect 1.8.0 → 1.9.0

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.
@@ -44,7 +44,7 @@ module.exports = function(core) {
44
44
  const isSecurityException = SecurityException.isSecurityException(err);
45
45
 
46
46
  if (isSecurityException && sourceContext) {
47
- const blockInfo = sourceContext.findings.securityException;
47
+ const blockInfo = sourceContext.securityException;
48
48
 
49
49
  sourceContext.block(...blockInfo);
50
50
  return;
@@ -70,7 +70,7 @@ module.exports = function(core) {
70
70
  const isSecurityException = SecurityException.isSecurityException(err);
71
71
 
72
72
  if (isSecurityException && sourceContext) {
73
- const blockInfo = sourceContext.findings.securityException;
73
+ const blockInfo = sourceContext.securityException;
74
74
 
75
75
  sourceContext.block(...blockInfo);
76
76
  return;
@@ -123,7 +123,7 @@ module.exports = function(core) {
123
123
  const isSecurityException = SecurityException.isSecurityException(err);
124
124
 
125
125
  if (isSecurityException && sourceContext) {
126
- const blockInfo = sourceContext.findings.securityException;
126
+ const blockInfo = sourceContext.securityException;
127
127
 
128
128
  sourceContext.block(...blockInfo);
129
129
  return;
@@ -62,7 +62,7 @@ module.exports = function(core) {
62
62
  if (!sourceContext) {
63
63
  normalHandler.call(this, err, request, reply);
64
64
  } else {
65
- const blockInfo = sourceContext.findings.securityException;
65
+ const blockInfo = sourceContext.securityException;
66
66
  sourceContext.block(...blockInfo);
67
67
  }
68
68
  } else {
@@ -39,7 +39,7 @@ module.exports = function (core) {
39
39
  const isSecurityException = SecurityException.isSecurityException(err);
40
40
 
41
41
  if (isSecurityException && sourceContext && err.output.statusCode !== 403) {
42
- const [mode, ruleId] = sourceContext.findings.securityException;
42
+ const [mode, ruleId] = sourceContext.securityException;
43
43
 
44
44
  err.output.statusCode = 403;
45
45
  err.reformat();
@@ -46,7 +46,7 @@ module.exports = function(core) {
46
46
 
47
47
  if (isSecurityException && sourceContext) {
48
48
  data.obj.body = '';
49
- const blockInfo = sourceContext.findings.securityException;
49
+ const blockInfo = sourceContext.securityException;
50
50
  sourceContext.block(...blockInfo);
51
51
  return;
52
52
  }
@@ -24,13 +24,14 @@ module.exports = function(core) {
24
24
  protect: {
25
25
  hardening,
26
26
  throwSecurityException,
27
- }
27
+ },
28
+ captureStacktrace,
28
29
  } = core;
29
30
 
30
31
  function getResults(sourceContext, ruleId) {
31
- let results = sourceContext.findings.hardeningResultsMap[ruleId];
32
+ let results = sourceContext.resultsMap[ruleId];
32
33
  if (!results) {
33
- results = sourceContext.findings.hardeningResultsMap[ruleId] = [];
34
+ results = sourceContext.resultsMap[ruleId] = [];
34
35
  }
35
36
  return results;
36
37
  }
@@ -38,7 +39,7 @@ module.exports = function(core) {
38
39
  hardening.handleUntrustedDeserialization = function(sourceContext, sinkContext) {
39
40
  const ruleId = 'untrusted-deserialization';
40
41
  const mode = sourceContext.policy[ruleId];
41
- const { name, value } = sinkContext;
42
+ const { name, value, stacktraceData } = sinkContext;
42
43
 
43
44
  if (mode === 'off') return;
44
45
 
@@ -48,14 +49,16 @@ module.exports = function(core) {
48
49
  const blocked = BLOCKING_MODES.includes(mode);
49
50
  const results = getResults(sourceContext, ruleId);
50
51
 
52
+ captureStacktrace(sinkContext, stacktraceData);
51
53
  results.push({
54
+ value: sinkContext.value,
52
55
  blocked,
53
- findings: { deserializer: name, command: false },
56
+ exploitMetadata: [{ deserializer: name, command: false }],
54
57
  sinkContext,
55
58
  });
56
59
 
57
60
  if (blocked) {
58
- sourceContext.findings.securityException = [mode, ruleId];
61
+ sourceContext.securityException = [mode, ruleId];
59
62
  throwSecurityException(sourceContext);
60
63
  }
61
64
  }
@@ -21,7 +21,6 @@ module.exports = function(core) {
21
21
  const {
22
22
  depHooks,
23
23
  patcher,
24
- captureStacktrace,
25
24
  protect,
26
25
  protect: {
27
26
  hardening
@@ -43,10 +42,11 @@ module.exports = function(core) {
43
42
 
44
43
  if (!sourceContext || !value) return;
45
44
 
46
- const sinkContext = captureStacktrace(
47
- { name: `${name}.${method}`, value },
48
- { constructorOpt: hooked, prependFrames: [orig] },
49
- );
45
+ const sinkContext = {
46
+ name: `${name}.${method}`,
47
+ value,
48
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
49
+ };
50
50
  hardening.handleUntrustedDeserialization(sourceContext, sinkContext);
51
51
  },
52
52
  });
package/lib/index.d.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  import { Logger } from '@contrast/logger';
17
17
  import { Sources } from '@contrast/scopes';
18
18
  import RequireHook from '@contrast/require-hook';
19
- import { RulesConfig, Messages, ReqData, ProtectMessage, Findings } from '@contrast/common';
19
+ import { RulesConfig, Messages, ReqData, ProtectMessage, ResultMap, ProtectRuleMode } from '@contrast/common';
20
20
  import { IncomingMessage, ServerResponse } from 'node:http';
21
21
  import { Config } from '@contrast/config';
22
22
  import * as http from 'node:http';
@@ -58,7 +58,10 @@ export interface ProtectRequestStore {
58
58
  };
59
59
  exclusions: any[]; // TODO
60
60
  virtualPatches: any[]; // TODO
61
- findings: Findings;
61
+ trackRequest: boolean;
62
+ securityException?: [mode: ProtectRuleMode, ruleId: string];
63
+ bodyType?: 'json' | 'urlencoded';
64
+ resultsMap: Partial<ResultMap>
62
65
  }
63
66
 
64
67
  export interface ConnectInputs {
package/lib/index.js CHANGED
@@ -16,7 +16,7 @@
16
16
  'use strict';
17
17
 
18
18
  const agentLib = require('@contrast/agent-lib');
19
- const { installChildComponentsSync } = require('@contrast/common');
19
+ const { callChildComponentMethodsSync } = require('@contrast/common');
20
20
 
21
21
  module.exports = function(core) {
22
22
  const protect = core.protect = {
@@ -35,7 +35,7 @@ module.exports = function(core) {
35
35
  require('./error-handlers')(core);
36
36
 
37
37
  protect.install = function() {
38
- installChildComponentsSync(protect);
38
+ callChildComponentMethodsSync(protect, 'install');
39
39
  };
40
40
 
41
41
  return protect;
@@ -17,7 +17,8 @@
17
17
 
18
18
  const {
19
19
  BLOCKING_MODES,
20
- simpleTraverse,
20
+ traverseKeysAndValues,
21
+ traverseValues,
21
22
  Rule,
22
23
  isString,
23
24
  ProtectRuleMode: { OFF },
@@ -199,7 +200,7 @@ module.exports = function(core) {
199
200
  const resultsList = [];
200
201
  const { UrlParameter } = agentLib.InputType;
201
202
 
202
- simpleTraverse(urlParams, function(path, type, value) {
203
+ traverseValues(urlParams, function(path, type, value) {
203
204
  // url param names are not checked.
204
205
  if (type !== 'Value') {
205
206
  return;
@@ -306,7 +307,7 @@ module.exports = function(core) {
306
307
 
307
308
  const block = commonObjectAnalyzer(sourceContext, parsedBody, inputTypes);
308
309
 
309
- sourceContext.findings.bodyType = bodyType;
310
+ sourceContext.bodyType = bodyType;
310
311
 
311
312
  if (block) {
312
313
  core.protect.throwSecurityException(sourceContext);
@@ -373,14 +374,14 @@ module.exports = function(core) {
373
374
  const { name, uuid } = vpEvaluators.get('metadata');
374
375
 
375
376
  if (vpEvaluators.size === 1 && uuid) {
376
- if (!sourceContext.findings.serverFeaturesResultsMap[ruleId]) {
377
- sourceContext.findings.serverFeaturesResultsMap[ruleId] = [];
377
+ if (!sourceContext.resultsMap[ruleId]) {
378
+ sourceContext.resultsMap[ruleId] = [];
378
379
  }
379
- sourceContext.findings.serverFeaturesResultsMap[ruleId].push({
380
+ sourceContext.resultsMap[ruleId].push({
380
381
  name,
381
382
  uuid
382
383
  });
383
- sourceContext.findings.securityException = ['block', ruleId];
384
+ sourceContext.securityException = ['block', ruleId];
384
385
  core.protect.throwSecurityException(sourceContext);
385
386
  }
386
387
  }
@@ -412,11 +413,11 @@ module.exports = function(core) {
412
413
 
413
414
  if (match) {
414
415
  logger.info(match, 'Found a matching IP to an entry in ipDeny list');
415
- if (!sourceContext.findings.serverFeaturesResultsMap[ruleId]) {
416
- sourceContext.findings.serverFeaturesResultsMap[ruleId] = [];
416
+ if (!sourceContext.resultsMap[ruleId]) {
417
+ sourceContext.resultsMap[ruleId] = [];
417
418
  }
418
419
 
419
- sourceContext.findings.serverFeaturesResultsMap[ruleId].push({
420
+ sourceContext.resultsMap[ruleId].push({
420
421
  ip: match.matchedIp,
421
422
  uuid: match.uuid,
422
423
  });
@@ -434,7 +435,7 @@ module.exports = function(core) {
434
435
  inputAnalysis.handleRequestEnd = function handleRequestEnd(sourceContext) {
435
436
  if (!config.protect.probe_analysis.enable || sourceContext.allowed) return;
436
437
 
437
- const { resultsMap } = sourceContext.findings;
438
+ const { resultsMap } = sourceContext;
438
439
  const probesRules = [Rule.CMD_INJECTION, Rule.PATH_TRAVERSAL, Rule.SQL_INJECTION, Rule.XXE];
439
440
  const props = {};
440
441
 
@@ -444,11 +445,11 @@ module.exports = function(core) {
444
445
  const {
445
446
  ruleId,
446
447
  blocked,
447
- details,
448
+ exploitMetadata,
448
449
  value,
449
450
  inputType
450
451
  } = resultByRuleId;
451
- if (blocked || !blocked && details.length > 0 || !probesRules.some(rule => rule === ruleId)) return;
452
+ if (blocked || !blocked && exploitMetadata.length > 0 || !probesRules.some(rule => rule === ruleId)) return;
452
453
 
453
454
  const { policy: { rulesMask } } = sourceContext;
454
455
 
@@ -514,19 +515,19 @@ module.exports = function(core) {
514
515
 
515
516
  // it's possible to optimize this if qs (or a similar package) is not loaded
516
517
  // or if none of the values of queryParams are objects. a quick '.includes()'
517
- // could be used to determine that. if none are objects then simpleTraverse()
518
+ // could be used to determine that. if none are objects then traverseKeysAndValues()
518
519
  // wouldn't be used, just a simple "for (const key in queryParams) {...}" to
519
520
  // check each key and value associated with the key.
520
521
  //
521
522
  // otoh, it's a fair amount of additional logic and the gain is likely to be
522
523
  // small, so it probably only makes sense to check if qs (or similar) is actually
523
- // in use. a benchmark of "for (const key in queryParams) {...}" vs simpleTraverse
524
+ // in use. a benchmark of "for (const key in queryParams) {...}" vs traverseKeysAndValues
524
525
  // should be created to see if, and in what cases, it makes sense.
525
526
  //
526
527
  // another day.
527
528
 
528
529
  /* eslint-disable-next-line complexity */
529
- simpleTraverse(object, function(path, type, value) {
530
+ traverseKeysAndValues(object, function(path, type, value) {
530
531
  let itemType;
531
532
  let isMongoQueryType;
532
533
  // this is a bit awkward now because nosql-injection-mongo is not integrated
@@ -708,10 +709,10 @@ function isResultExcluded(sourceContext, result) {
708
709
  * @returns {undefined|[String]} undefined to permit else [mode, rule] to block.
709
710
  */
710
711
  function mergeFindings(sourceContext, newFindings) {
711
- const { findings, policy } = sourceContext;
712
+ const { policy, securityException, resultsMap } = sourceContext;
712
713
 
713
714
  if (!newFindings.trackRequest) {
714
- return findings.securityException;
715
+ return securityException;
715
716
  }
716
717
 
717
718
  newFindings.resultsList = newFindings.resultsList.filter(
@@ -720,18 +721,18 @@ function mergeFindings(sourceContext, newFindings) {
720
721
 
721
722
  normalizeFindings(policy, newFindings);
722
723
 
723
- findings.trackRequest = findings.trackRequest || newFindings.trackRequest;
724
- findings.securityException = findings.securityException || newFindings.securityException;
724
+ sourceContext.trackRequest = sourceContext.trackRequest || newFindings.trackRequest;
725
+ sourceContext.securityException = sourceContext.securityException || newFindings.securityException;
725
726
 
726
727
  // merge them into a ruleId-indexed map (pojo)
727
728
  for (const result of newFindings.resultsList) {
728
- if (!findings.resultsMap[result.ruleId]) {
729
- findings.resultsMap[result.ruleId] = [];
729
+ if (!resultsMap[result.ruleId]) {
730
+ resultsMap[result.ruleId] = [];
730
731
  }
731
- findings.resultsMap[result.ruleId].push(result);
732
+ resultsMap[result.ruleId].push(result);
732
733
  }
733
734
 
734
- return findings.securityException;
735
+ return sourceContext.securityException;
735
736
  }
736
737
 
737
738
  //
@@ -749,7 +750,7 @@ function normalizeFindings(policy, findings) {
749
750
  r.blocked = false;
750
751
 
751
752
  // sink analysis will add findings here
752
- r.details = [];
753
+ r.exploitMetadata = [];
753
754
 
754
755
  // apply exclusions here.
755
756
  //
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { installChildComponentsSync } = require('@contrast/common');
18
+ const { callChildComponentMethodsSync } = require('@contrast/common');
19
19
 
20
20
  module.exports = function(core) {
21
21
  const inputAnalysis = core.protect.inputAnalysis = {};
@@ -47,7 +47,7 @@ module.exports = function(core) {
47
47
  require('./ip-analysis')(core);
48
48
 
49
49
  inputAnalysis.install = function() {
50
- installChildComponentsSync(inputAnalysis);
50
+ callChildComponentMethodsSync(inputAnalysis, 'install');
51
51
  };
52
52
 
53
53
  return inputAnalysis;
@@ -214,12 +214,6 @@ class HttpInstrumentation {
214
214
  method: reqData.method,
215
215
  };
216
216
 
217
- // only add queries if it's known that 'qs' or equivalent won't be used.
218
- /* c8 ignore next 3 */
219
- if (reqData.standardUrlParsing) {
220
- connectInputs.queries = reqData.queries;
221
- }
222
-
223
217
  if (inputAnalysis.virtualPatchesEvaluators?.length) {
224
218
  store.protect.virtualPatchesEvaluators.push(...inputAnalysis.virtualPatchesEvaluators.map((e) => new Map(e)));
225
219
  }
@@ -20,21 +20,31 @@ const {
20
20
  ProtectRuleMode: { OFF },
21
21
  BLOCKING_MODES,
22
22
  isString,
23
- simpleTraverse
23
+ traverseKeys,
24
+ traverseKeysAndValues,
24
25
  } = require('@contrast/common');
25
26
 
26
27
  module.exports = function(core) {
27
- const { protect: { agentLib, inputTracing, throwSecurityException } } = core;
28
+ const {
29
+ protect: {
30
+ agentLib,
31
+ inputTracing,
32
+ throwSecurityException
33
+ },
34
+ captureStacktrace,
35
+ } = core;
28
36
 
29
37
  function handleFindings(sourceContext, sinkContext, ruleId, result, findings) {
30
- result.details.push({ sinkContext, findings });
38
+ const { stacktraceData } = sinkContext;
39
+ captureStacktrace(sinkContext, stacktraceData);
40
+ result.exploitMetadata.push({ sinkContext, findings });
31
41
 
32
42
  const mode = sourceContext.policy[ruleId];
33
43
 
34
44
  if (BLOCKING_MODES.includes(mode)) {
35
45
  result.blocked = true;
36
46
  const blockInfo = [mode, ruleId];
37
- sourceContext.findings.securityException = blockInfo;
47
+ sourceContext.securityException = blockInfo;
38
48
  throwSecurityException(sourceContext);
39
49
  }
40
50
  }
@@ -137,10 +147,13 @@ module.exports = function(core) {
137
147
 
138
148
  for (const result of stringInjectionResults) {
139
149
  if (typeof sinkContext.value === 'object') {
140
- simpleTraverse(sinkContext.value, function(path, type, value) {
150
+ traverseKeysAndValues(sinkContext.value, function(path, type, value) {
141
151
  if (type !== 'Key' && !agentLib.isMongoQueryType(value)) return;
142
152
 
143
153
  stringFindings = handleStringValue(result, sinkContext.value[value], agentLib);
154
+
155
+ // halt traversal
156
+ return true;
144
157
  });
145
158
  } else if (typeof sinkContext.value === 'string') {
146
159
  stringFindings = handleStringValue(result, sinkContext.value, agentLib);
@@ -149,11 +162,11 @@ module.exports = function(core) {
149
162
  if (stringFindings) {
150
163
  const nosqlInjectionResult = { ...result, ruleId, mappedId: ruleId };
151
164
 
152
- const nosqlInjectionResults = sourceContext.findings.resultsMap[ruleId];
165
+ const nosqlInjectionResults = sourceContext.resultsMap[ruleId];
153
166
  if (Array.isArray(nosqlInjectionResults)) {
154
167
  nosqlInjectionResults.push(nosqlInjectionResult);
155
168
  } else {
156
- sourceContext.findings.resultsMap[ruleId] = [nosqlInjectionResult];
169
+ sourceContext.resultsMap[ruleId] = [nosqlInjectionResult];
157
170
  }
158
171
 
159
172
  handleFindings(sourceContext, sinkContext, ruleId, nosqlInjectionResult, stringFindings);
@@ -222,7 +235,7 @@ module.exports = function(core) {
222
235
  const findings = idx !== -1 ? { value: sinkContext.value } : null;
223
236
 
224
237
  if (findings) {
225
- result.details.push({ sinkContext, findings });
238
+ result.exploitMetadata.push({ sinkContext, findings });
226
239
  }
227
240
  }
228
241
  };
@@ -241,18 +254,13 @@ function getResultsByRuleId(ruleId, context) {
241
254
  if (context.policy[ruleId] === OFF) {
242
255
  return;
243
256
  }
244
- return context.findings.resultsMap[ruleId];
257
+ return context.resultsMap[ruleId];
245
258
  }
246
259
 
247
260
  function handleObjectValue(result, object) {
248
- if (typeof object !== 'object') {
249
- return null;
250
- }
251
261
  let findings = null;
252
- simpleTraverse(object, function(path, type, value) {
253
- if (type !== 'Key' || findings) {
254
- return;
255
- }
262
+
263
+ traverseKeys(object, function(path, type, value) {
256
264
  // the result value is the key that was found
257
265
  if (result.key === value) {
258
266
  // does the object at this path equal the user input?
@@ -267,6 +275,9 @@ function handleObjectValue(result, object) {
267
275
  const end = start + value.length;
268
276
  const inputBoundaryIndex = 0;
269
277
  findings = { start, end, boundaryOverrunIndex: start, inputBoundaryIndex };
278
+
279
+ // halt traversal
280
+ return true;
270
281
  }
271
282
  }
272
283
  });
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { installChildComponentsSync } = require('@contrast/common');
18
+ const { callChildComponentMethodsSync } = require('@contrast/common');
19
19
 
20
20
  module.exports = function(core) {
21
21
  const inputTracing = core.protect.inputTracing = {};
@@ -38,7 +38,7 @@ module.exports = function(core) {
38
38
  // TODO: NODE-2360 (oracledb)
39
39
 
40
40
  inputTracing.install = function() {
41
- installChildComponentsSync(inputTracing);
41
+ callChildComponentMethodsSync(inputTracing, 'install');
42
42
  };
43
43
 
44
44
  return inputTracing;
@@ -23,11 +23,31 @@ module.exports = function(core) {
23
23
  scopes: { instrumentation },
24
24
  patcher,
25
25
  depHooks,
26
- captureStacktrace,
27
- protect,
28
- protect: { inputTracing }
26
+ protect: { getSourceContext, inputTracing }
29
27
  } = core;
30
28
 
29
+ function pre({ args, name, hooked, orig }) {
30
+ if (instrumentation.isLocked()) return;
31
+
32
+ const sourceContext = getSourceContext('child_process');
33
+ const value = args[0];
34
+
35
+ if (!sourceContext || !value || !isString(value)) return;
36
+
37
+ const sinkContext = {
38
+ name,
39
+ value,
40
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
41
+ };
42
+
43
+ inputTracing.handleCommandInjection(sourceContext, sinkContext);
44
+ core.protect.semanticAnalysis.handleCommandInjectionCommandBackdoors(sourceContext, sinkContext);
45
+ core.protect.semanticAnalysis.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContext);
46
+ core.protect.semanticAnalysis.handleCmdInjectionSemanticDangerous(sourceContext, sinkContext);
47
+ core.protect.semanticAnalysis.handlePathTraversalFileSecurityBypass(sourceContext, sinkContext);
48
+ }
49
+
50
+
31
51
  function install() {
32
52
  depHooks.resolve({ name: 'child_process' }, cp => {
33
53
  ['exec', 'execSync'].forEach((method) => {
@@ -35,27 +55,7 @@ module.exports = function(core) {
35
55
  patcher.patch(cp, method, {
36
56
  name,
37
57
  patchType,
38
- pre({ args, hooked, orig }) {
39
- if (instrumentation.isLocked()) return;
40
-
41
- const sourceContext = protect.getSourceContext('child_process');
42
- const value = args[0];
43
-
44
- if (!sourceContext || !value || !isString(value)) return;
45
-
46
- const sinkContext = captureStacktrace(
47
- { name, value },
48
- { constructorOpt: hooked, prependFrames: [orig] }
49
- );
50
-
51
- inputTracing.handleCommandInjection(sourceContext, sinkContext);
52
- // To evade code duplication we are using these INPUT TRACING instrumentation
53
- // to do the checks for SEMANTIC ANALYSIS too
54
- core.protect.semanticAnalysis.handleCommandInjectionCommandBackdoors(sourceContext, sinkContext);
55
- core.protect.semanticAnalysis.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContext);
56
- core.protect.semanticAnalysis.handleCmdInjectionSemanticDangerous(sourceContext, sinkContext);
57
- core.protect.semanticAnalysis.handlePathTraversalFileSecurityBypass(sourceContext, sinkContext);
58
- }
58
+ pre
59
59
  });
60
60
  });
61
61
  });
@@ -23,7 +23,6 @@ module.exports = function(core) {
23
23
  logger,
24
24
  scopes: { instrumentation },
25
25
  patcher,
26
- captureStacktrace,
27
26
  protect,
28
27
  protect: { inputTracing }
29
28
  } = core;
@@ -45,10 +44,11 @@ module.exports = function(core) {
45
44
 
46
45
  if (!sourceContext || !value || !isString(value)) return;
47
46
 
48
- const sinkContext = captureStacktrace(
49
- { name: 'eval', value },
50
- { constructorOpt: hooked, prependFrames: [orig] }
51
- );
47
+ const sinkContext = {
48
+ name: 'eval',
49
+ value,
50
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
51
+ };
52
52
  inputTracing.ssjsInjection(sourceContext, sinkContext);
53
53
  }
54
54
  });
@@ -64,7 +64,6 @@ module.exports = function(core) {
64
64
  scopes: { instrumentation },
65
65
  patcher,
66
66
  depHooks,
67
- captureStacktrace,
68
67
  protect,
69
68
  protect: { inputTracing }
70
69
  } = core;
@@ -101,10 +100,11 @@ module.exports = function(core) {
101
100
  // don't need to necessarily need to lock it here - there are no
102
101
  // lower-level calls that we instrument
103
102
  for (const value of values) {
104
- const sinkContext = captureStacktrace(
105
- { name, value },
106
- { constructorOpt: hooked, prependFrames: [orig] }
107
- );
103
+ const sinkContext = {
104
+ name,
105
+ value,
106
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
107
+ };
108
108
  inputTracing.handlePathTraversal(sourceContext, sinkContext);
109
109
  core.protect.semanticAnalysis.handlePathTraversalFileSecurityBypass(sourceContext, sinkContext);
110
110
  }
@@ -23,7 +23,6 @@ module.exports = function(core) {
23
23
  logger,
24
24
  scopes: { instrumentation },
25
25
  patcher,
26
- captureStacktrace,
27
26
  protect,
28
27
  protect: { inputTracing }
29
28
  } = core;
@@ -46,10 +45,12 @@ module.exports = function(core) {
46
45
 
47
46
  if (!sourceContext || !fnBody || !isString(fnBody)) return;
48
47
 
49
- const sinkContext = captureStacktrace(
50
- { name: 'Function', value: fnBody },
51
- { constructorOpt: hooked, prependFrames: [orig] }
52
- );
48
+ const sinkContext = {
49
+ name: 'Function',
50
+ value: fnBody,
51
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
52
+ };
53
+
53
54
  inputTracing.ssjsInjection(sourceContext, sinkContext);
54
55
  }
55
56
  })
@@ -22,7 +22,6 @@ module.exports = function(core) {
22
22
  scopes: { instrumentation },
23
23
  patcher,
24
24
  depHooks,
25
- captureStacktrace,
26
25
  protect,
27
26
  protect: { inputTracing }
28
27
  } = core;
@@ -44,10 +43,11 @@ module.exports = function(core) {
44
43
  const value = data.args[0]?.toString();
45
44
  if (!value) return;
46
45
 
47
- const sinkContext = captureStacktrace(
48
- { name, value },
49
- { constructorOpt: data.hooked }
50
- );
46
+ const sinkContext = {
47
+ name,
48
+ value,
49
+ stacktraceData: { constructorOpt: data.hooked },
50
+ };
51
51
  inputTracing.handleReflectedXss(sourceContext, sinkContext);
52
52
  }
53
53
  });