@contrast/assess 1.10.0 → 1.12.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 (119) hide show
  1. package/lib/dataflow/index.js +1 -2
  2. package/lib/dataflow/propagation/common.js +1 -1
  3. package/lib/dataflow/propagation/index.js +2 -1
  4. package/lib/dataflow/propagation/install/JSON/index.js +1 -1
  5. package/lib/dataflow/propagation/install/JSON/parse-fn.js +1 -1
  6. package/lib/dataflow/propagation/install/JSON/parse.js +3 -5
  7. package/lib/dataflow/propagation/install/JSON/stringify.js +3 -2
  8. package/lib/dataflow/propagation/install/array-prototype-join.js +3 -2
  9. package/lib/dataflow/propagation/install/buffer.js +3 -5
  10. package/lib/dataflow/propagation/install/contrast-methods/add.js +3 -2
  11. package/lib/dataflow/propagation/install/contrast-methods/index.js +1 -1
  12. package/lib/dataflow/propagation/install/contrast-methods/number.js +1 -1
  13. package/lib/dataflow/propagation/install/contrast-methods/string.js +3 -5
  14. package/lib/dataflow/propagation/install/contrast-methods/tag.js +3 -5
  15. package/lib/dataflow/propagation/install/decode-uri-component.js +3 -2
  16. package/lib/dataflow/propagation/install/ejs/escape-xml.js +3 -2
  17. package/lib/dataflow/propagation/install/ejs/index.js +1 -1
  18. package/lib/dataflow/propagation/install/encode-uri-component.js +3 -2
  19. package/lib/dataflow/propagation/install/escape-html.js +3 -2
  20. package/lib/dataflow/propagation/install/escape.js +3 -2
  21. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +3 -2
  22. package/lib/dataflow/propagation/install/isnumeric-0.js +1 -1
  23. package/lib/dataflow/propagation/install/mongoose/common.js +20 -0
  24. package/lib/dataflow/propagation/install/mongoose/index.js +5 -9
  25. package/lib/dataflow/propagation/install/mongoose/schema-map.js +149 -0
  26. package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +162 -0
  27. package/lib/dataflow/propagation/install/mongoose/schema-string.js +91 -39
  28. package/lib/dataflow/propagation/install/mysql-connection-escape.js +3 -2
  29. package/lib/dataflow/propagation/install/parse-int.js +1 -1
  30. package/lib/dataflow/propagation/install/path/basename.js +3 -5
  31. package/lib/dataflow/propagation/install/path/common.js +1 -1
  32. package/lib/dataflow/propagation/install/path/index.js +1 -1
  33. package/lib/dataflow/propagation/install/path/join-and-resolve.js +3 -5
  34. package/lib/dataflow/propagation/install/path/normalize.js +3 -5
  35. package/lib/dataflow/propagation/install/pug/index.js +1 -1
  36. package/lib/dataflow/propagation/install/pug-runtime-escape.js +3 -2
  37. package/lib/dataflow/propagation/install/querystring/index.js +1 -1
  38. package/lib/dataflow/propagation/install/querystring/parse.js +3 -2
  39. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +180 -0
  40. package/lib/dataflow/propagation/install/sequelize.js +3 -5
  41. package/lib/dataflow/propagation/install/sql-template-strings.js +3 -2
  42. package/lib/dataflow/propagation/install/string/concat.js +3 -2
  43. package/lib/dataflow/propagation/install/string/format-methods.js +3 -2
  44. package/lib/dataflow/propagation/install/string/html-methods.js +3 -2
  45. package/lib/dataflow/propagation/install/string/index.js +66 -1
  46. package/lib/dataflow/propagation/install/string/match-all.js +236 -0
  47. package/lib/dataflow/propagation/install/string/match.js +83 -37
  48. package/lib/dataflow/propagation/install/string/replace.js +4 -3
  49. package/lib/dataflow/propagation/install/string/slice.js +3 -2
  50. package/lib/dataflow/propagation/install/string/split.js +3 -2
  51. package/lib/dataflow/propagation/install/string/substring.js +3 -2
  52. package/lib/dataflow/propagation/install/string/trim.js +3 -2
  53. package/lib/dataflow/propagation/install/unescape.js +3 -2
  54. package/lib/dataflow/propagation/install/url/domain-parsers.js +3 -2
  55. package/lib/dataflow/propagation/install/url/index.js +3 -1
  56. package/lib/dataflow/propagation/install/url/parse.js +132 -0
  57. package/lib/dataflow/propagation/install/url/searchParams.js +140 -0
  58. package/lib/dataflow/propagation/install/url/url.js +11 -53
  59. package/lib/dataflow/propagation/install/validator/hooks.js +3 -2
  60. package/lib/dataflow/propagation/install/validator/index.js +1 -1
  61. package/lib/dataflow/propagation/install/validator/methods.js +1 -1
  62. package/lib/dataflow/sinks/common.js +1 -1
  63. package/lib/dataflow/sinks/index.js +1 -1
  64. package/lib/dataflow/sinks/install/child-process.js +2 -2
  65. package/lib/dataflow/sinks/install/eval.js +2 -2
  66. package/lib/dataflow/sinks/install/express/index.js +1 -1
  67. package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +3 -3
  68. package/lib/dataflow/sinks/install/fastify/index.js +1 -1
  69. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +2 -2
  70. package/lib/dataflow/sinks/install/fs.js +2 -2
  71. package/lib/dataflow/sinks/install/function.js +2 -2
  72. package/lib/dataflow/sinks/install/http/index.js +1 -1
  73. package/lib/dataflow/sinks/install/http/request.js +2 -2
  74. package/lib/dataflow/sinks/install/http/server-response.js +2 -2
  75. package/lib/dataflow/sinks/install/koa/index.js +1 -1
  76. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +2 -2
  77. package/lib/dataflow/sinks/install/marsdb.js +2 -2
  78. package/lib/dataflow/sinks/install/mongodb.js +33 -26
  79. package/lib/dataflow/sinks/install/mssql.js +2 -2
  80. package/lib/dataflow/sinks/install/mysql.js +3 -3
  81. package/lib/dataflow/sinks/install/postgres.js +2 -2
  82. package/lib/dataflow/sinks/install/sequelize.js +2 -2
  83. package/lib/dataflow/sinks/install/sqlite3.js +2 -2
  84. package/lib/dataflow/sinks/install/vm.js +2 -2
  85. package/lib/dataflow/sources/common.js +1 -1
  86. package/lib/dataflow/sources/handler.js +3 -3
  87. package/lib/dataflow/sources/index.js +1 -1
  88. package/lib/dataflow/sources/install/body-parser1.js +1 -1
  89. package/lib/dataflow/sources/install/busboy1.js +1 -1
  90. package/lib/dataflow/sources/install/cookie-parser1.js +1 -1
  91. package/lib/dataflow/sources/install/express/index.js +1 -1
  92. package/lib/dataflow/sources/install/express/params.js +1 -1
  93. package/lib/dataflow/sources/install/express/parsedUrl.js +1 -1
  94. package/lib/dataflow/sources/install/fastify/fastify.js +1 -1
  95. package/lib/dataflow/sources/install/fastify/index.js +1 -1
  96. package/lib/dataflow/sources/install/formidable1.js +1 -1
  97. package/lib/dataflow/sources/install/http.js +2 -2
  98. package/lib/dataflow/sources/install/koa/index.js +1 -1
  99. package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +1 -1
  100. package/lib/dataflow/sources/install/koa/koa-routers.js +1 -1
  101. package/lib/dataflow/sources/install/koa/koa2.js +1 -1
  102. package/lib/dataflow/sources/install/qs6.js +1 -1
  103. package/lib/dataflow/sources/install/querystring.js +1 -1
  104. package/lib/dataflow/tag-utils.js +1 -1
  105. package/lib/dataflow/tracker.js +2 -6
  106. package/lib/dataflow/utils/is-safe-content-type.js +1 -1
  107. package/lib/dataflow/utils/is-vulnerable.js +1 -1
  108. package/lib/{dataflow/event-factory.js → event-factory.js} +58 -2
  109. package/lib/index.js +4 -2
  110. package/lib/response-scanning/handlers/index.js +36 -30
  111. package/lib/response-scanning/handlers/utils.js +1 -1
  112. package/lib/response-scanning/index.js +1 -1
  113. package/lib/response-scanning/install/http.js +3 -3
  114. package/lib/session-configuration/common.js +19 -0
  115. package/lib/session-configuration/handlers.js +86 -0
  116. package/lib/session-configuration/index.js +6 -9
  117. package/lib/session-configuration/install/express-session.js +131 -0
  118. package/package.json +3 -3
  119. package/lib/session-configuration/install/http.js +0 -79
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -27,10 +27,8 @@ module.exports = function(core) {
27
27
  patcher,
28
28
  depHooks,
29
29
  assess: {
30
- dataflow: {
31
- tracker,
32
- eventFactory: { createPropagationEvent },
33
- },
30
+ eventFactory: { createPropagationEvent },
31
+ dataflow: { tracker },
34
32
  },
35
33
  } = core;
36
34
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -26,7 +26,8 @@ module.exports = function(core) {
26
26
  patcher,
27
27
  depHooks,
28
28
  assess: {
29
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
29
+ eventFactory: { createPropagationEvent },
30
+ dataflow: { tracker }
30
31
  }
31
32
  } = core;
32
33
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -26,7 +26,8 @@ module.exports = function(core) {
26
26
  scopes: { sources, instrumentation },
27
27
  patcher,
28
28
  assess: {
29
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
29
+ eventFactory: { createPropagationEvent },
30
+ dataflow: { tracker }
30
31
  }
31
32
  } = core;
32
33
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -22,7 +22,8 @@ module.exports = function(core) {
22
22
  scopes: { sources, instrumentation },
23
23
  patcher,
24
24
  assess: {
25
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
25
+ eventFactory: { createPropagationEvent },
26
+ dataflow: { tracker }
26
27
  }
27
28
  } = core;
28
29
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -36,7 +36,8 @@ module.exports = function(core) {
36
36
  scopes: { sources, instrumentation },
37
37
  patcher,
38
38
  assess: {
39
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
39
+ eventFactory: { createPropagationEvent },
40
+ dataflow: { tracker }
40
41
  }
41
42
  } = core;
42
43
  function adjustTags(method, objTags, argLength, argTags = null) {
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -16,21 +16,86 @@
16
16
  'use strict';
17
17
 
18
18
  const { callChildComponentMethodsSync } = require('@contrast/common');
19
+ const { inspect, split } = require('@contrast/common');
19
20
 
20
21
  module.exports = function(core) {
22
+ const {
23
+ scopes: { sources, instrumentation },
24
+ patcher,
25
+ assess: {
26
+ eventFactory: { createPropagationEvent },
27
+ dataflow: { tracker }
28
+ }
29
+ } = core;
21
30
  const stringInstrumentation = core.assess.dataflow.propagation.stringInstrumentation = {
22
31
  install() {
23
32
  callChildComponentMethodsSync(stringInstrumentation, 'install');
24
33
  },
25
34
  uninstall() {
26
35
  callChildComponentMethodsSync(stringInstrumentation, 'uninstall');
36
+ },
37
+ utils: {
38
+ patchCustomMatcher
27
39
  }
28
40
  };
29
41
 
42
+ function patchCustomMatcher(matcherFn, objInfo, methodArg, name, patchType) {
43
+ const [, , methodName] = split(name, '.');
44
+
45
+ return patcher.patch(matcherFn, {
46
+ name,
47
+ patchType,
48
+ pre(data) {
49
+ const { args: origArgs, hooked, orig } = data;
50
+ if (
51
+ !origArgs.length ||
52
+ typeof origArgs[0] !== 'string' ||
53
+ !sources.getStore()?.assess ||
54
+ instrumentation.isLocked()
55
+ ) return;
56
+
57
+ const args = [{
58
+ value: inspect(methodArg),
59
+ tracked: false
60
+ }];
61
+
62
+ const event = createPropagationEvent({
63
+ name,
64
+ moduleName: 'String',
65
+ methodName: `prototype.${methodName}`,
66
+ context: `'${objInfo.value}'.${methodName}(${args[0].value})`,
67
+ history: [objInfo],
68
+ object: {
69
+ value: objInfo.value,
70
+ tracked: true,
71
+ },
72
+ args,
73
+ tags: objInfo.tags,
74
+ result: undefined,
75
+ stacktraceOpts: {
76
+ constructorOpt: hooked,
77
+ prependFrames: [orig]
78
+ },
79
+ source: 'P',
80
+ target: 'P'
81
+ });
82
+
83
+ if (!event) return;
84
+
85
+ const { extern } = tracker.track(objInfo.value, event);
86
+
87
+ if (extern) {
88
+ origArgs[0] = extern;
89
+ }
90
+ }
91
+ });
92
+ }
93
+
30
94
  require('./concat')(core);
31
95
  require('./format-methods')(core);
32
96
  require('./html-methods')(core);
33
97
  require('./match')(core);
98
+ require('./match-all')(core);
34
99
  require('./replace')(core);
35
100
  require('./split')(core);
36
101
  require('./slice')(core);
@@ -0,0 +1,236 @@
1
+ /*
2
+ * Copyright: 2023 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
+ const { inspect } = require('@contrast/common');
18
+ const { patchType } = require('../../common');
19
+ const { createSubsetTags } = require('../../../tag-utils');
20
+
21
+ module.exports = function(core) {
22
+ const {
23
+ scopes: { sources, instrumentation },
24
+ patcher,
25
+ assess: {
26
+ eventFactory: { createPropagationEvent },
27
+ dataflow: {
28
+ tracker,
29
+ propagation: { stringInstrumentation },
30
+ },
31
+ },
32
+ } = core;
33
+ const name = 'String.prototype.matchAll';
34
+
35
+ function createPropagationEventForMatch({
36
+ objInfo,
37
+ startIdx,
38
+ match,
39
+ untrackedResult,
40
+ metadata,
41
+ }) {
42
+ const tags = createSubsetTags(objInfo.tags, startIdx, match.length);
43
+
44
+ if (!tags) return;
45
+
46
+ const { arg, hooked, orig } = metadata;
47
+
48
+ return createPropagationEvent({
49
+ name,
50
+ moduleName: 'String',
51
+ methodName: 'prototype.matchAll',
52
+ context: `'${objInfo.value}'.matcAll(${arg})`,
53
+ history: [objInfo],
54
+ object: {
55
+ value: objInfo.value,
56
+ tracked: true,
57
+ },
58
+ args: [
59
+ {
60
+ value: arg,
61
+ tracked: false,
62
+ },
63
+ ],
64
+ tags,
65
+ result: {
66
+ value: inspect(untrackedResult),
67
+ tracked: false,
68
+ },
69
+ stacktraceOpts: {
70
+ constructorOpt: hooked,
71
+ prependFrames: [orig],
72
+ },
73
+ source: 'O',
74
+ target: 'R',
75
+ });
76
+ }
77
+
78
+ return (stringInstrumentation.matchAll = {
79
+ install() {
80
+ patcher.patch(String.prototype, 'matchAll', {
81
+ name,
82
+ patchType,
83
+ around(origFn, data) {
84
+ const { args, obj, hooked, orig } = data;
85
+
86
+ if (
87
+ !obj ||
88
+ !args[0] ||
89
+ typeof obj !== 'string' ||
90
+ !sources.getStore()?.assess ||
91
+ instrumentation.isLocked()
92
+ )
93
+ return origFn();
94
+
95
+ const objInfo = tracker.getData(obj);
96
+
97
+ if (!objInfo) return origFn();
98
+
99
+ if (
100
+ !(args[0] instanceof RegExp) &&
101
+ typeof args[0][Symbol.matchAll] === 'function'
102
+ ) {
103
+ args[0][Symbol.matchAll] =
104
+ stringInstrumentation.utils.patchCustomMatcher(
105
+ args[0][Symbol.matchAll],
106
+ objInfo,
107
+ args[0],
108
+ name,
109
+ patchType
110
+ );
111
+
112
+ return origFn();
113
+ }
114
+
115
+ const result = origFn();
116
+ const newResult = {};
117
+
118
+ function next() {
119
+ const origRes = core.scopes.instrumentation.run(
120
+ { lock: true },
121
+ () => result.next()
122
+ );
123
+
124
+ if (!origRes?.value) return { done: true };
125
+
126
+ const resValue = origRes.value;
127
+ const untrackedResult = [...resValue];
128
+ untrackedResult.groups = resValue.groups && { ...resValue.groups };
129
+ untrackedResult.input = objInfo.value;
130
+ untrackedResult.index = resValue.index;
131
+ resValue.indices && (untrackedResult.indices = resValue.indices);
132
+
133
+ let searchIdx = resValue.index;
134
+ const metadata = { arg: inspect(args[0]), hooked, orig };
135
+
136
+ for (let i = 0; i < resValue.length; i++) {
137
+ let match = resValue[i];
138
+
139
+ if (!match) continue;
140
+
141
+ if (match === obj) {
142
+ // There is a case where the match
143
+ // is the whole original string in which case the value here is
144
+ // externalized and we need to make sure to track
145
+ // the non-exterrnalized one
146
+ match = objInfo.value;
147
+ }
148
+
149
+ const startIdx = objInfo.value.indexOf(match, searchIdx);
150
+ const event = createPropagationEventForMatch({
151
+ objInfo,
152
+ startIdx,
153
+ match,
154
+ untrackedResult,
155
+ metadata,
156
+ });
157
+
158
+ if (i > 0) {
159
+ searchIdx = startIdx + match.length;
160
+ }
161
+
162
+ if (!event) continue;
163
+
164
+ const { extern } = tracker.track(match, event);
165
+
166
+ if (extern) {
167
+ resValue[i] = extern;
168
+ }
169
+ }
170
+
171
+ if (resValue.groups) {
172
+ Object.keys(resValue.groups).forEach((key) => {
173
+ let res = resValue.groups[key];
174
+ let event;
175
+
176
+ if (!res) return;
177
+
178
+ if (res === obj) {
179
+ res = objInfo.value;
180
+ event = createPropagationEventForMatch({
181
+ objInfo,
182
+ startIdx: 0,
183
+ match: res,
184
+ untrackedResult,
185
+ metadata,
186
+ });
187
+ } else {
188
+ const startIdx = objInfo.value.indexOf(res, resValue.index);
189
+ event = createPropagationEventForMatch({
190
+ objInfo,
191
+ startIdx,
192
+ match: res,
193
+ untrackedResult,
194
+ metadata,
195
+ });
196
+ }
197
+
198
+ if (event) {
199
+ const { extern } = tracker.track(res, event);
200
+ if (extern) {
201
+ resValue.groups[key] = extern;
202
+ }
203
+ }
204
+ });
205
+ }
206
+
207
+ return { value: resValue, done: origRes.done };
208
+ }
209
+
210
+ Object.defineProperty(newResult, Symbol.iterator, {
211
+ enumerable: false,
212
+ value() {
213
+ return {
214
+ next,
215
+ };
216
+ },
217
+ });
218
+ Object.defineProperty(newResult, Symbol.toStringTag, {
219
+ enumerable: false,
220
+ value: 'RegExp String Iterator',
221
+ });
222
+
223
+ Object.setPrototypeOf(newResult, {
224
+ ...Object.getPrototypeOf(result),
225
+ next,
226
+ });
227
+
228
+ return newResult;
229
+ },
230
+ });
231
+ },
232
+ uninstall() {
233
+ String.prototype.matchAll = patcher.unwrap(String.prototype.matchAll);
234
+ },
235
+ });
236
+ };
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -23,28 +23,32 @@ module.exports = function(core) {
23
23
  scopes: { sources, instrumentation },
24
24
  patcher,
25
25
  assess: {
26
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
27
- }
26
+ eventFactory: { createPropagationEvent },
27
+ dataflow: {
28
+ tracker,
29
+ propagation: { stringInstrumentation },
30
+ },
31
+ },
28
32
  } = core;
33
+ const name = 'String.prototype.match';
29
34
 
30
35
  function getPropagationEvent(data, res, objInfo, start) {
31
- const { name, args: origArgs, result, hooked, orig } = data;
36
+ const { args: origArgs, result, hooked, orig } = data;
32
37
  const tags = createSubsetTags(objInfo.tags, start, res.length);
33
38
  if (!tags) return;
34
39
 
35
- const args = origArgs.map((arg) => {
36
- const argInfo = tracker.getData(arg);
37
- return {
38
- value: argInfo ? argInfo.value : inspect(arg),
39
- tracked: !!argInfo
40
- };
41
- });
40
+ const args = [
41
+ {
42
+ value: inspect(origArgs[0]),
43
+ tracked: false,
44
+ },
45
+ ];
42
46
 
43
47
  return createPropagationEvent({
44
48
  name,
45
49
  moduleName: 'String',
46
50
  methodName: 'prototype.match',
47
- context: `'${objInfo.value}'.match(${join(args.map(a => a.value), ', ')})`,
51
+ context: `'${objInfo.value}'.match(${args[0].value})`,
48
52
  history: [objInfo],
49
53
  object: {
50
54
  value: objInfo.value,
@@ -54,48 +58,79 @@ module.exports = function(core) {
54
58
  tags,
55
59
  result: {
56
60
  value: join(result),
57
- tracked: false
61
+ tracked: false,
58
62
  },
59
63
  stacktraceOpts: {
60
64
  constructorOpt: hooked,
61
- prependFrames: [orig]
65
+ prependFrames: [orig],
62
66
  },
63
67
  source: 'O',
64
- target: 'R'
68
+ target: 'R',
65
69
  });
66
70
  }
67
71
 
68
- return core.assess.dataflow.propagation.stringInstrumentation.match = {
72
+ return (stringInstrumentation.match = {
69
73
  install() {
70
- const name = 'String.prototype.match';
71
-
72
74
  patcher.patch(String.prototype, 'match', {
73
75
  name,
74
76
  patchType,
75
- post(data) {
76
- const { args, obj, result } = data;
77
+ around(origFn, data) {
78
+ const { args, obj } = data;
77
79
  if (
78
80
  !obj ||
79
- !result ||
80
- args.length === 0 ||
81
- result.length === 0 ||
82
- !sources.getStore() ||
81
+ !args.length ||
82
+ !sources.getStore()?.assess ||
83
83
  typeof obj !== 'string' ||
84
84
  instrumentation.isLocked() ||
85
- (args.length === 1 && args[0] == null)
86
- ) return;
85
+ (args.length === 1 && !args[0])
86
+ )
87
+ return origFn();
87
88
 
88
89
  const objInfo = tracker.getData(obj);
89
- if (!objInfo) return;
90
+
91
+ if (!objInfo) return origFn();
92
+
93
+ if (
94
+ !(args[0] instanceof RegExp) &&
95
+ typeof args[0][Symbol.match] === 'function'
96
+ ) {
97
+ args[0][Symbol.match] =
98
+ stringInstrumentation.utils.patchCustomMatcher(
99
+ args[0][Symbol.match],
100
+ objInfo,
101
+ args[0],
102
+ name,
103
+ patchType
104
+ );
105
+
106
+ return origFn();
107
+ }
108
+
109
+ const result = (data.result = core.scopes.instrumentation.run(
110
+ { lock: true },
111
+ () => origFn()
112
+ ));
113
+
114
+ if (!result) return result;
90
115
 
91
116
  let idx = 0;
92
117
  const hasCaptureGroups = 'groups' in result;
93
118
  for (let i = 0; i < result.length; i++) {
94
- const res = result[i];
95
- if (!res || res === obj) continue;
96
- const start = obj.indexOf(res, idx);
97
- idx += hasCaptureGroups ? 0 : start + res.length;
98
- const event = getPropagationEvent(data, res, objInfo, start);
119
+ let res = result[i];
120
+ let event;
121
+
122
+ if (!res) continue;
123
+
124
+ if (res === obj) {
125
+ res = objInfo.value;
126
+ event = getPropagationEvent(data, res, objInfo, 0);
127
+ } else {
128
+ const start = obj.indexOf(res, idx);
129
+ idx += hasCaptureGroups && i === 0 ? 0 : res.length;
130
+
131
+ event = getPropagationEvent(data, res, objInfo, start);
132
+ }
133
+
99
134
  if (event) {
100
135
  const { extern } = tracker.track(res, event);
101
136
  if (extern) {
@@ -105,10 +140,19 @@ module.exports = function(core) {
105
140
  }
106
141
  if (hasCaptureGroups && result.groups) {
107
142
  Object.keys(result.groups).forEach((key) => {
108
- const res = result.groups[key];
109
- if (!res || res === obj) return;
110
- const start = obj.indexOf(res);
111
- const event = getPropagationEvent(data, res, objInfo, start);
143
+ let res = result.groups[key];
144
+ let event;
145
+
146
+ if (!res) return;
147
+
148
+ if (res === obj) {
149
+ res = objInfo.value;
150
+ event = getPropagationEvent(data, res, objInfo, 0);
151
+ } else {
152
+ const start = obj.indexOf(res);
153
+ event = getPropagationEvent(data, res, objInfo, start);
154
+ }
155
+
112
156
  if (event) {
113
157
  const { extern } = tracker.track(res, event);
114
158
  if (extern) {
@@ -117,11 +161,13 @@ module.exports = function(core) {
117
161
  }
118
162
  });
119
163
  }
164
+
165
+ return data.result;
120
166
  },
121
167
  });
122
168
  },
123
169
  uninstall() {
124
170
  String.prototype.match = patcher.unwrap(String.prototype.match);
125
171
  },
126
- };
172
+ });
127
173
  };
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -28,7 +28,8 @@ module.exports = function(core) {
28
28
  const {
29
29
  patcher,
30
30
  assess: {
31
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
31
+ eventFactory: { createPropagationEvent },
32
+ dataflow: { tracker }
32
33
  },
33
34
  scopes: { sources, instrumentation }
34
35
  } = core;
@@ -101,7 +102,7 @@ module.exports = function(core) {
101
102
  replacement = replaceSpecialCharacters(String(replacement), parsedArgs, data._replacementType);
102
103
 
103
104
  data._replacementInfo = tracker.getData(replacement);
104
- if (data._replacement) {
105
+ if (data._replacementInfo) {
105
106
  data._history.add(data._replacementInfo);
106
107
  }
107
108
  return { replacement, replacementInfo: data._replacementInfo };
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -22,7 +22,8 @@ module.exports = function(core) {
22
22
  scopes: { sources, instrumentation },
23
23
  patcher,
24
24
  assess: {
25
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
25
+ eventFactory: { createPropagationEvent },
26
+ dataflow: { tracker }
26
27
  }
27
28
  } = core;
28
29
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -25,7 +25,8 @@ module.exports = function(core) {
25
25
  scopes: { sources, instrumentation },
26
26
  patcher,
27
27
  assess: {
28
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
28
+ eventFactory: { createPropagationEvent },
29
+ dataflow: { tracker }
29
30
  }
30
31
  } = core;
31
32
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright: 2022 Contrast Security, Inc
2
+ * Copyright: 2023 Contrast Security, Inc
3
3
  * Contact: support@contrastsecurity.com
4
4
  * License: Commercial
5
5
 
@@ -24,7 +24,8 @@ module.exports = function(core) {
24
24
  scopes: { sources, instrumentation },
25
25
  patcher,
26
26
  assess: {
27
- dataflow: { tracker, eventFactory: { createPropagationEvent } }
27
+ eventFactory: { createPropagationEvent },
28
+ dataflow: { tracker }
28
29
  }
29
30
  } = core;
30
31