@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.
@@ -20,7 +20,7 @@ const {
20
20
  BLOCKING_MODES,
21
21
  ProtectRuleMode: { OFF },
22
22
  InputType,
23
- simpleTraverse
23
+ traverseValues,
24
24
  } = require('@contrast/common');
25
25
 
26
26
  const {
@@ -38,22 +38,27 @@ const getRuleResults = function(obj, prop) {
38
38
  // See files in protect/lib/input-tracing/install/.
39
39
 
40
40
  module.exports = function(core) {
41
- const { protect: { agentLib, semanticAnalysis, throwSecurityException } } = core;
41
+ const { protect: { agentLib, semanticAnalysis, throwSecurityException }, captureStacktrace } = core;
42
42
 
43
43
  function handleResult(sourceContext, sinkContext, ruleId, mode, finding) {
44
+ const { value, stacktraceData } = sinkContext;
45
+ captureStacktrace(sinkContext, stacktraceData);
44
46
  const result = {
45
47
  blocked: false,
46
- findings: { command: sinkContext.value },
48
+ ruleId,
49
+ value,
50
+ mappedId: ruleId,
51
+ exploitMetadata: [{ command: value }],
47
52
  sinkContext,
48
53
  ...finding
49
54
  };
50
55
 
51
- getRuleResults(sourceContext.findings.semanticResultsMap, ruleId).push(result);
56
+ getRuleResults(sourceContext.resultsMap, ruleId).push(result);
52
57
 
53
58
  if (BLOCKING_MODES.includes(mode)) {
54
59
  result.blocked = true;
55
60
  const blockInfo = [mode, ruleId];
56
- sourceContext.findings.securityException = blockInfo;
61
+ sourceContext.securityException = blockInfo;
57
62
  throwSecurityException(sourceContext);
58
63
  }
59
64
  }
@@ -101,7 +106,7 @@ module.exports = function(core) {
101
106
 
102
107
  if (agentLib.isDangerousPath(sinkContext.value, true)) {
103
108
  handleResult(sourceContext, sinkContext, Rule.PATH_TRAVERSAL_SEMANTIC_FILE_SECURITY_BYPASS, mode, {
104
- findings: { path: sinkContext.value }
109
+ exploitMetadata: [{ path: sinkContext.value }]
105
110
  });
106
111
  }
107
112
  };
@@ -113,7 +118,7 @@ module.exports = function(core) {
113
118
  const findings = findExternalEntities(sinkContext.value);
114
119
  if (findings.entities.length) {
115
120
  handleResult(sourceContext, sinkContext, Rule.XXE, mode, {
116
- findings,
121
+ exploitMetadata: [findings],
117
122
  });
118
123
  }
119
124
  };
@@ -141,17 +146,15 @@ function findBackdoorInjection(sourceContext, command) {
141
146
  [InputType.HEADER]: sourceContext.reqData.headers,
142
147
  };
143
148
 
144
- let found = false;
149
+ let found;
145
150
  for (const inputType in valuesOfInterest) {
151
+ if (found) break;
152
+
146
153
  const values = valuesOfInterest[inputType];
147
154
 
148
155
  if (values && Object.keys(values).length) {
149
- simpleTraverse(values, (path, type, value, obj) => {
150
- if (
151
- !found &&
152
- type === 'Value' &&
153
- isBackdoorDetected(value, command)
154
- ) {
156
+ traverseValues(values, (path, type, value, obj) => {
157
+ if (isBackdoorDetected(value, command)) {
155
158
  let key;
156
159
  if (inputType === InputType.HEADER) {
157
160
  key = obj[path[0] - 1];
@@ -165,6 +168,9 @@ function findBackdoorInjection(sourceContext, command) {
165
168
  path: path.slice(0, -1),
166
169
  value: command
167
170
  };
171
+
172
+ // halt traversal
173
+ return true;
168
174
  }
169
175
  });
170
176
  }
@@ -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
  /**
21
21
  * SEMANTIC ANALYSIS is a STAGE of Protect.
@@ -37,11 +37,8 @@ module.exports = function(core) {
37
37
  require('./install/libxmljs')(core);
38
38
 
39
39
  semanticAnalysis.install = function() {
40
- installChildComponentsSync(semanticAnalysis);
40
+ callChildComponentMethodsSync(semanticAnalysis, 'install');
41
41
  };
42
42
 
43
- // There is no `.install()` method as this STAGE does not introduce side effects on its own,
44
- // it uses the instrumentation that's already in place for INPUT TRACING.
45
-
46
43
  return semanticAnalysis;
47
44
  };
@@ -26,7 +26,6 @@ module.exports = function(core) {
26
26
  logger,
27
27
  protect: { semanticAnalysis },
28
28
  protect,
29
- captureStacktrace
30
29
  } = core;
31
30
 
32
31
  function install() {
@@ -60,10 +59,11 @@ module.exports = function(core) {
60
59
  // see: https://help.semmle.com/wiki/display/JS/XML+external+entity+expansion
61
60
  if (!sourceContext || !value || !isString(value) || !args[1].noent) return;
62
61
 
63
- const sinkContext = captureStacktrace(
64
- { name: 'libxmljs.parseXmlString', value },
65
- { constructorOpt: hooked, prependFrames: [orig] }
66
- );
62
+ const sinkContext = {
63
+ name: 'libxmljs.parseXmlString',
64
+ value,
65
+ stacktraceData: { constructorOpt: hooked, prependFrames: [orig] },
66
+ };
67
67
 
68
68
  try {
69
69
  semanticAnalysis.handleXXE(sourceContext, sinkContext);
@@ -24,9 +24,7 @@ module.exports = function(core) {
24
24
  if (!sourceContext) return;
25
25
 
26
26
  const {
27
- findings: {
28
- securityException: [mode, ruleId]
29
- }
27
+ securityException: [mode, ruleId]
30
28
  } = sourceContext;
31
29
 
32
30
  const err = securityException.create();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/protect",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Contrast service providing framework-agnostic Protect support",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -18,11 +18,11 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@contrast/agent-lib": "^5.1.0",
21
- "@contrast/common": "1.1.4",
22
- "@contrast/core": "1.7.0",
23
- "@contrast/esm-hooks": "1.3.0",
21
+ "@contrast/common": "1.2.0",
22
+ "@contrast/core": "1.8.0",
23
+ "@contrast/esm-hooks": "1.4.0",
24
24
  "@contrast/scopes": "1.2.0",
25
25
  "ipaddr.js": "^2.0.1",
26
26
  "semver": "^7.3.7"
27
27
  }
28
- }
28
+ }