@contrast/protect 1.2.0 → 1.3.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.
Files changed (47) hide show
  1. package/lib/cli-rewriter.js +15 -0
  2. package/lib/error-handlers/constants.js +15 -0
  3. package/lib/error-handlers/index.js +17 -0
  4. package/lib/error-handlers/install/express4.js +90 -0
  5. package/lib/error-handlers/install/fastify3.js +15 -0
  6. package/lib/error-handlers/install/koa2.js +15 -0
  7. package/lib/esm-loader.mjs +15 -0
  8. package/lib/index.d.ts +145 -19
  9. package/lib/index.js +15 -0
  10. package/lib/input-analysis/constants.js +20 -0
  11. package/lib/input-analysis/handlers.js +33 -10
  12. package/lib/input-analysis/index.js +36 -3
  13. package/lib/input-analysis/install/body-parser1.js +130 -0
  14. package/lib/input-analysis/install/cookie-parser1.js +82 -0
  15. package/lib/input-analysis/install/express4.js +108 -0
  16. package/lib/input-analysis/install/fastify3.js +47 -19
  17. package/lib/input-analysis/install/formidable1.js +73 -0
  18. package/lib/input-analysis/install/http.js +18 -1
  19. package/lib/input-analysis/install/koa-body5.js +68 -0
  20. package/lib/input-analysis/install/koa-bodyparser4.js +68 -0
  21. package/lib/input-analysis/install/koa2.js +26 -25
  22. package/lib/input-analysis/install/multer1.js +89 -0
  23. package/lib/input-analysis/install/qs6.js +61 -0
  24. package/lib/input-analysis/install/universal-cookie4.js +56 -0
  25. package/lib/input-tracing/constants.js +15 -0
  26. package/lib/input-tracing/handlers/index.js +154 -59
  27. package/lib/input-tracing/index.js +17 -0
  28. package/lib/input-tracing/install/child-process.js +16 -1
  29. package/lib/input-tracing/install/fs.js +17 -2
  30. package/lib/input-tracing/install/mongodb.js +233 -0
  31. package/lib/input-tracing/install/mysql.js +18 -2
  32. package/lib/input-tracing/install/postgres.js +15 -0
  33. package/lib/input-tracing/install/sequelize.js +15 -0
  34. package/lib/input-tracing/install/sqlite3.js +15 -0
  35. package/lib/make-response-blocker.js +15 -0
  36. package/lib/make-source-context.js +18 -0
  37. package/lib/security-exception.js +15 -0
  38. package/lib/throw-security-exception.js +17 -6
  39. package/lib/utils.js +14 -18
  40. package/package.json +7 -7
  41. package/lib/input-analysis/install/co-body.js +0 -51
  42. package/lib/input-analysis/install/cookie-parser.js +0 -48
  43. package/lib/input-analysis/install/formidable.js +0 -53
  44. package/lib/input-analysis/install/multer.js +0 -52
  45. package/lib/input-analysis/install/qs.js +0 -40
  46. package/lib/input-analysis/install/universal-cookie.js +0 -34
  47. package/lib/input-tracing/handlers/nosql-injection-mongo.js +0 -48
@@ -1,7 +1,24 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
1
16
  'use strict';
2
17
 
18
+ const { patchType } = require('../constants');
19
+
3
20
  /**
4
- * Function that exports an install method to patch Fastify framework with our instrumentation
21
+ * Function that exports an install method to patch Koa framework with our instrumentation
5
22
  * @param {Object} core - the core Contrast object in v5
6
23
  * @return {Object} object with install method and the other relative functions exported for testing purposes
7
24
  */
@@ -19,14 +36,6 @@ module.exports = (core) => {
19
36
  */
20
37
  function install() {
21
38
  depHooks.resolve({ name: 'koa', version: '>=2.3.0' }, (Koa) => {
22
- const coBodyPatch = require('./co-body.js')(core);
23
- const multerPatch = require('./multer')(core);
24
- const formidablePatch = require('./formidable')(core);
25
- const qsPatch = require('./qs')(core);
26
- const cookieParserPatch = require('./cookie-parser')(core);
27
- const universalCookiePatch = require('./universal-cookie')(core);
28
-
29
-
30
39
  function contrastStartMiddleware(ctx, next) {
31
40
  if (ctx.query && Object.keys(ctx.query).length) {
32
41
  const sourceContext = sources.getStore()?.protect;
@@ -37,7 +46,6 @@ module.exports = (core) => {
37
46
  sourceContext.parsedQuery = ctx.query;
38
47
  inputAnalysis.handleQueryParams(sourceContext, ctx.query);
39
48
  }
40
-
41
49
  }
42
50
  return next();
43
51
  }
@@ -47,7 +55,7 @@ module.exports = (core) => {
47
55
 
48
56
  patcher.patch(Koa.prototype, 'use', {
49
57
  name: 'Koa.Application',
50
- patchType: 'framework-patch',
58
+ patchType,
51
59
  pre({ obj: app }) {
52
60
  // if not already inserted, insert the initial middleware.
53
61
  if (
@@ -66,7 +74,7 @@ module.exports = (core) => {
66
74
  (layer) => {
67
75
  layer.prototype = patcher.patch(layer.prototype, 'params', {
68
76
  name: `[${router}].layer.prototype`,
69
- patchType: 'framework-patch',
77
+ patchType,
70
78
  post({ result }) {
71
79
  const sourceContext = sources.getStore()?.protect;
72
80
 
@@ -90,15 +98,15 @@ module.exports = (core) => {
90
98
  const { default: cookieParser } = koaCookie;
91
99
  koaCookie.default = patcher.patch(cookieParser, {
92
100
  name: 'koa-cookie',
93
- patchType: 'framework-patch',
101
+ patchType,
94
102
  post(data) {
95
103
  data.result = patcher.patch(data.result, {
96
104
  name: 'koa-cookie',
97
- patchType: 'framework-patch',
105
+ patchType,
98
106
  pre(data) {
99
107
  const [ctx, origNext] = data.args;
100
108
 
101
- async function contrastNext() {
109
+ async function contrastNext(origErr) {
102
110
  const sourceContext = sources.getStore()?.protect;
103
111
 
104
112
  if (!sourceContext) {
@@ -110,7 +118,7 @@ module.exports = (core) => {
110
118
  }
111
119
  }
112
120
 
113
- await origNext();
121
+ await origNext(origErr);
114
122
  }
115
123
 
116
124
  data.args[1] = contrastNext;
@@ -119,19 +127,12 @@ module.exports = (core) => {
119
127
  }
120
128
  });
121
129
  });
122
-
123
- coBodyPatch.install();
124
- multerPatch.install();
125
- formidablePatch.install();
126
- qsPatch.install();
127
- cookieParserPatch.install();
128
- universalCookiePatch.install();
129
130
  });
130
131
  }
131
132
 
132
- const koaInstrumentation = inputAnalysis.koaInstrumentation = {
133
+ const koa2Instrumentation = inputAnalysis.koa2Instrumentation = {
133
134
  install
134
135
  };
135
136
 
136
- return koaInstrumentation;
137
+ return koa2Instrumentation;
137
138
  };
@@ -0,0 +1,89 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const { patchType } = require('../constants');
19
+ const { isSecurityException } = require('../../security-exception');
20
+
21
+ module.exports = (core) => {
22
+ const {
23
+ depHooks,
24
+ patcher,
25
+ logger,
26
+ scopes: { sources, wrap },
27
+ protect: { inputAnalysis },
28
+ } = core;
29
+
30
+ // Patch `multer`
31
+ function install() {
32
+ depHooks.resolve({ name: 'multer', file: 'lib/make-middleware.js' }, (multerMakeMiddleware) => patcher.patch(multerMakeMiddleware, {
33
+ name: 'multer.make-middleware',
34
+ patchType,
35
+ post(data) {
36
+ data.result = patcher.patch(data.result, {
37
+ name: 'multerMiddleware',
38
+ patchType,
39
+ pre(data) {
40
+ const [req, , origNext] = data.args;
41
+
42
+ // We are getting the sourceContext here because in the time of calling
43
+ // the contrastNext() method the context is lost
44
+ const sourceContext = sources.getStore()?.protect;
45
+ if (!sourceContext) {
46
+ logger.debug('source context not available in `multer` hook');
47
+ return;
48
+ }
49
+
50
+ function contrastNext(origErr) {
51
+ let securityException;
52
+
53
+ if (req.body) {
54
+ sourceContext.parsedBody = req.body;
55
+
56
+ try {
57
+ inputAnalysis.handleParsedBody(sourceContext, req.body);
58
+ } catch (err) {
59
+ if (isSecurityException(err)) {
60
+ securityException = err;
61
+ } else {
62
+ logger.error({ err }, 'Unexpected error during input analysis');
63
+ }
64
+ }
65
+ }
66
+
67
+ if (req.file || req.files) {
68
+ logger.debug('Check for vulnerable filename upload nyi');
69
+ // TODO: NODE-2601
70
+ }
71
+
72
+ const error = securityException || origErr;
73
+
74
+ origNext(error);
75
+ }
76
+
77
+ data.args[2] = wrap(contrastNext);
78
+ }
79
+ });
80
+ }
81
+ }));
82
+ }
83
+
84
+ const multer1Instrumentation = inputAnalysis.multer1Instrumentation = {
85
+ install
86
+ };
87
+
88
+ return multer1Instrumentation;
89
+ };
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const { patchType } = require('../constants');
19
+
20
+ module.exports = (core) => {
21
+ const {
22
+ depHooks,
23
+ patcher,
24
+ logger,
25
+ scopes: { sources },
26
+ protect: { inputAnalysis },
27
+ } = core;
28
+
29
+ // Patch `qs`
30
+ function install() {
31
+ depHooks.resolve({ name: 'qs' },
32
+ (qs) => patcher.patch(qs, 'parse', {
33
+ name: 'qs',
34
+ patchType,
35
+ post({ args, result }) {
36
+ if (result && Object.keys(result).length) {
37
+ const sourceContext = sources.getStore()?.protect;
38
+
39
+ if (!sourceContext) {
40
+ logger.debug('source context not available in `qs` hook');
41
+
42
+ // We need to run analysis for the `qs` result only when it's used as a query parser.
43
+ // `qs` is used also for parsing bodies, but these cases we handle individually with
44
+ // the respective library that's using it (e.g. `formidable`, `co-body`) because in
45
+ // some cases its use is optional and we cannot rely on it.
46
+ } else if (sourceContext.reqData?.queries === args[0]) {
47
+ sourceContext.parsedQuery = result;
48
+ inputAnalysis.handleQueryParams(sourceContext, result);
49
+ }
50
+ }
51
+ }
52
+ })
53
+ );
54
+ }
55
+
56
+ const qs6Instrumentation = inputAnalysis.qs6Instrumentation = {
57
+ install
58
+ };
59
+
60
+ return qs6Instrumentation;
61
+ };
@@ -0,0 +1,56 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
16
+ 'use strict';
17
+
18
+ const { patchType } = require('../constants');
19
+
20
+ module.exports = (core) => {
21
+ const {
22
+ depHooks,
23
+ patcher,
24
+ logger,
25
+ scopes: { sources },
26
+ protect: { inputAnalysis },
27
+ } = core;
28
+
29
+
30
+ // Patch `universal-cookie` package
31
+ function install() {
32
+ depHooks.resolve({ name: 'universal-cookie', file: 'cjs/utils.js' }, (uCookieUtils) => patcher.patch(uCookieUtils, 'parseCookies', {
33
+ name: 'universal-cookie.utils',
34
+ patchType,
35
+ post({ result }) {
36
+ if (result && Object.keys(result).length) {
37
+ const sourceContext = sources.getStore()?.protect;
38
+
39
+ if (!sourceContext) {
40
+ logger.debug('source context not available in `universal-cookie` hook');
41
+ } else {
42
+ sourceContext.parsedCookies = result;
43
+ inputAnalysis.handleCookies(sourceContext, result);
44
+ }
45
+ }
46
+ }
47
+ })
48
+ );
49
+ }
50
+
51
+ const universalCookie4Instrumentation = inputAnalysis.universalCookie4Instrumentation = {
52
+ install
53
+ };
54
+
55
+ return universalCookie4Instrumentation;
56
+ };
@@ -1,3 +1,18 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
1
16
  'use strict';
2
17
 
3
18
  module.exports = {
@@ -1,5 +1,23 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
1
16
  'use strict';
2
17
 
18
+ const util = require('util');
19
+ const { simpleTraverse } = require('../../utils');
20
+
3
21
  module.exports = function(core) {
4
22
  const { protect: { agentLib, inputTracing, throwSecurityException } } = core;
5
23
 
@@ -9,87 +27,90 @@ module.exports = function(core) {
9
27
  * @param {object} context async storage data for protect
10
28
  * @returns {AnalysisResult[]}
11
29
  */
12
- inputTracing.getResultsByRuleId = function(ruleId, context) {
30
+ function getResultsByRuleId(ruleId, context) {
31
+ if (context.rules.agentLibRules[ruleId].mode === 'off') {
32
+ return;
33
+ }
13
34
  return context.findings.resultsMap[ruleId];
14
- };
35
+ }
15
36
 
16
- /**
17
- * Given a ruleId and an analysis function, wrap the analysis function
18
- * with common setup and post-processing code.
19
- */
20
- inputTracing.handlerFactory = function(ruleId, analysisFn) {
21
- /**
22
- * This is the common API for INPUT TRACING instrumentation.
23
- * @param {object} sourceContext
24
- * @param {object} sinkContext
25
- */
26
- return function(sourceContext, sinkContext) {
27
- if (sourceContext.rules.agentLibRules[ruleId].mode === 'off') {
28
- return;
29
- }
37
+ function handleFindings(sourceContext, sinkContext, ruleId, result, findings) {
38
+ result.details.push({ sinkContext, findings });
30
39
 
31
- const results = inputTracing.getResultsByRuleId(ruleId, sourceContext);
32
- if (!results) return;
40
+ const { mode } = sourceContext.rules.agentLibRules[ruleId];
33
41
 
34
- for (const result of results) {
35
- const findings = analysisFn(result, sinkContext);
42
+ if (['block', 'block_at_perimeter'].includes(mode)) {
43
+ result.blocked = true;
44
+ const blockInfo = [mode, ruleId];
45
+ sourceContext.findings.securityException = blockInfo;
46
+ throwSecurityException(sourceContext);
47
+ }
48
+ }
36
49
 
37
- if (findings) {
38
- result.details.push({ sinkContext, findings });
50
+ inputTracing.handlePathTraversal = function(sourceContext, sinkContext) {
51
+ const ruleId = 'path-traversal';
52
+ const results = getResultsByRuleId(ruleId, sourceContext);
39
53
 
40
- if (sourceContext.rules.agentLibRules[ruleId].mode === 'block') {
41
- result.blocked = true;
42
- const blockInfo = ['block', ruleId];
43
- sourceContext.findings.securityException = blockInfo;
44
- throwSecurityException(sourceContext);
45
- }
46
- }
47
- }
48
- };
49
- };
54
+ if (!results) return;
50
55
 
51
- inputTracing.handlePathTraversal = inputTracing.handlerFactory(
52
- 'path-traversal',
53
- function(result, sinkContext) {
56
+ for (const result of results) {
54
57
  const idx = sinkContext.value.indexOf(result.value);
55
- return idx !== -1 ? { path: sinkContext.value } : null;
58
+ const findings = idx !== -1 ? { path: sinkContext.value } : null;
59
+
60
+ if (findings) {
61
+ handleFindings(sourceContext, sinkContext, ruleId, result, findings);
62
+ }
56
63
  }
57
- );
64
+ };
65
+
66
+ inputTracing.handleCommandInjection = function(sourceContext, sinkContext) {
67
+ const ruleId = 'cmd-injection';
68
+ const results = getResultsByRuleId(ruleId, sourceContext);
58
69
 
59
- inputTracing.handleCommandInjection = inputTracing.handlerFactory(
60
- 'cmd-injection',
61
- function(result, sinkContext) {
70
+ if (!results) return;
71
+
72
+ for (const result of results) {
73
+ let findings = null;
62
74
  const inputIndex = sinkContext.value.indexOf(result.value);
63
75
  if (inputIndex !== -1) {
64
- return agentLib.checkCommandInjectionSink(
76
+ findings = agentLib.checkCommandInjectionSink(
65
77
  inputIndex,
66
78
  result.value.length,
67
79
  sinkContext.value,
68
80
  );
69
81
  }
82
+
83
+ if (findings) {
84
+ handleFindings(sourceContext, sinkContext, ruleId, result, findings);
85
+ }
70
86
  }
71
- );
87
+ };
88
+
89
+ inputTracing.handleSqlInjection = function(sourceContext, sinkContext) {
90
+ const ruleId = 'sql-injection';
91
+ const results = getResultsByRuleId(ruleId, sourceContext);
72
92
 
73
- inputTracing.handleSqlInjection = inputTracing.handlerFactory(
74
- 'sql-injection',
75
- function(result, sinkContext) {
76
- let analysis = null;
93
+ if (!results) return;
94
+
95
+ for (const result of results) {
96
+ let findings = null;
77
97
 
78
98
  const inputIndex = sinkContext.value.indexOf(result.value);
99
+
79
100
  // if the user input is not in the sink input, there is nothing to do.
80
101
  if (inputIndex === -1) {
81
- return analysis;
102
+ continue;
82
103
  }
83
104
 
84
105
  if (inputIndex === 0 && sinkContext.value === result.value) {
85
- analysis = {
106
+ findings = {
86
107
  startIndex: 0,
87
108
  endIndex: result.value.length - 1,
88
109
  overrunIndex: 0,
89
110
  boundaryIndex: 0,
90
111
  };
91
112
  } else {
92
- analysis = agentLib.checkSqlInjectionSink(
113
+ findings = agentLib.checkSqlInjectionSink(
93
114
  inputIndex,
94
115
  result.value.length,
95
116
  2,
@@ -97,21 +118,95 @@ module.exports = function(core) {
97
118
  );
98
119
  }
99
120
 
100
- return analysis;
121
+ if (findings) {
122
+ handleFindings(sourceContext, sinkContext, ruleId, result, findings);
123
+ }
101
124
  }
102
- );
125
+ };
126
+
127
+ inputTracing.nosqlInjectionMongo = function(sourceContext, sinkContext) {
128
+ const ruleId = 'nosql-injection-mongo';
129
+ const expansionResults = getResultsByRuleId(ruleId, sourceContext);
130
+ const stringResults = getResultsByRuleId('ssjs-injection', sourceContext);
103
131
 
104
- inputTracing.nosqlInjectionMongo = inputTracing.handlerFactory(
105
- 'nosql-injection-mongo', require('./nosql-injection-mongo')
106
- );
132
+ if (expansionResults) {
133
+ let expansionFindings = null;
134
+ for (const result of expansionResults) {
135
+ expansionFindings = handleObjectValue(result, sinkContext.value);
107
136
 
108
- inputTracing.ssjsInjection = inputTracing.handlerFactory(
109
- 'ssjs-injection',
110
- function(results, sinkContext) {
111
- return null;
137
+ if (expansionFindings) {
138
+ handleFindings(sourceContext, sinkContext, ruleId, result, expansionFindings);
139
+ }
140
+ }
112
141
  }
113
- );
142
+
143
+ if (stringResults) {
144
+ let stringFindings = null;
145
+ for (const result of stringResults) {
146
+ stringFindings = handleStringValue(result, sinkContext.value);
147
+
148
+ if (stringFindings) {
149
+ handleFindings(sourceContext, sinkContext, ruleId, result, stringFindings);
150
+ }
151
+ }
152
+ }
153
+ };
154
+
155
+ inputTracing.ssjsInjection = function(sourceContext, sinkContext) {
156
+ // 'ssjs-injection' NYI
157
+ return null;
158
+ };
114
159
 
115
160
  return inputTracing;
116
161
  };
117
162
 
163
+ function handleObjectValue(result, object) {
164
+ if (typeof object !== 'object') {
165
+ return null;
166
+ }
167
+ let findings = null;
168
+ simpleTraverse(object, function(path, type, value) {
169
+ if (type !== 'Key' || findings) {
170
+ return;
171
+ }
172
+ // the result value is the key that was found
173
+ if (result.key === value) {
174
+ // does the object at this path equal the user input?
175
+ let obj = object;
176
+ for (const p of path) {
177
+ obj = obj[p];
178
+ }
179
+ obj = obj[value];
180
+ // does the found object in the query equal the saved object?
181
+ if (util.isDeepStrictEqual(obj, result.mongoContext.inputToCheck)) {
182
+ findings = { key: value };
183
+ }
184
+ }
185
+ });
186
+
187
+ return findings;
188
+ }
189
+
190
+ function handleStringValue(result, string) {
191
+ if (typeof string !== 'string') {
192
+ return null;
193
+ }
194
+ let findings = null;
195
+
196
+ const inputIndex = string.indexOf(result.value);
197
+ // if the user input is not in the sink input, there is nothing to do.
198
+ if (inputIndex === -1) {
199
+ return findings;
200
+ }
201
+
202
+ if (inputIndex === 0 && string === result.value) {
203
+ findings = {
204
+ startIndex: 0,
205
+ endIndex: result.value.length - 1,
206
+ overrunIndex: 0,
207
+ boundaryIndex: 0,
208
+ };
209
+ }
210
+
211
+ return findings;
212
+ }
@@ -1,3 +1,18 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
1
16
  'use strict';
2
17
 
3
18
  /**
@@ -19,12 +34,14 @@ module.exports = function(core) {
19
34
  require('./install/child-process')(core);
20
35
  require('./install/mysql')(core);
21
36
  require('./install/postgres')(core);
37
+ require('./install/mongodb')(core);
22
38
 
23
39
  inputTracing.install = function() {
24
40
  inputTracing.fsInstrumentation.install();
25
41
  inputTracing.cpInstrumentation.install();
26
42
  inputTracing.mysqlInstrumentation.install();
27
43
  inputTracing.postgresInstrumentation.install();
44
+ inputTracing.mongodbInstrumentation.install();
28
45
  // TODO: NODE-2360 (2260?)
29
46
  };
30
47
 
@@ -1,3 +1,18 @@
1
+ /*
2
+ * Copyright: 2022 Contrast Security, Inc
3
+ * Contact: support@contrastsecurity.com
4
+ * License: Commercial
5
+
6
+ * NOTICE: This Software and the patented inventions embodied within may only be
7
+ * used as part of Contrast Security’s commercial offerings. Even though it is
8
+ * made available through public repositories, use of this Software is subject to
9
+ * the applicable End User Licensing Agreement found at
10
+ * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ * between Contrast Security and the End User. The Software may not be reverse
12
+ * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ * way not consistent with the End User License Agreement.
14
+ */
15
+
1
16
  'use strict';
2
17
 
3
18
  const { isString } = require('@contrast/common');
@@ -30,7 +45,7 @@ module.exports = function(core) {
30
45
 
31
46
  const sinkContext = captureStacktrace(
32
47
  { name, value },
33
- { constructorOpt: data.hooked }
48
+ { constructorOpt: data.hooked, prependFrames: [data.orig] }
34
49
  );
35
50
  inputTracing.handleCommandInjection(sourceContext, sinkContext);
36
51
  }