@contrast/assess 1.4.0 → 1.6.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 (59) hide show
  1. package/lib/dataflow/event-factory.js +41 -83
  2. package/lib/dataflow/index.js +0 -1
  3. package/lib/dataflow/propagation/install/array-prototype-join.js +3 -3
  4. package/lib/dataflow/propagation/install/contrast-methods/add.js +23 -16
  5. package/lib/dataflow/propagation/install/contrast-methods/tag.js +30 -22
  6. package/lib/dataflow/propagation/install/decode-uri-component.js +8 -5
  7. package/lib/dataflow/propagation/install/ejs/escape-xml.js +8 -5
  8. package/lib/dataflow/propagation/install/encode-uri-component.js +3 -3
  9. package/lib/dataflow/propagation/install/escape-html.js +10 -7
  10. package/lib/dataflow/propagation/install/escape.js +8 -5
  11. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +8 -5
  12. package/lib/dataflow/propagation/install/mysql-connection-escape.js +8 -5
  13. package/lib/dataflow/propagation/install/pug-runtime-escape.js +3 -3
  14. package/lib/dataflow/propagation/install/querystring/parse.js +11 -6
  15. package/lib/dataflow/propagation/install/sql-template-strings.js +3 -3
  16. package/lib/dataflow/propagation/install/string/concat.js +4 -4
  17. package/lib/dataflow/propagation/install/string/format-methods.js +2 -2
  18. package/lib/dataflow/propagation/install/string/html-methods.js +5 -5
  19. package/lib/dataflow/propagation/install/string/index.js +1 -0
  20. package/lib/dataflow/propagation/install/string/match.js +3 -3
  21. package/lib/dataflow/propagation/install/string/replace.js +9 -5
  22. package/lib/dataflow/propagation/install/string/slice.js +104 -0
  23. package/lib/dataflow/propagation/install/string/split.js +4 -4
  24. package/lib/dataflow/propagation/install/string/substring.js +6 -4
  25. package/lib/dataflow/propagation/install/string/trim.js +2 -2
  26. package/lib/dataflow/propagation/install/unescape.js +8 -5
  27. package/lib/dataflow/propagation/install/url/domain-parsers.js +3 -3
  28. package/lib/dataflow/propagation/install/validator/hooks.js +2 -2
  29. package/lib/dataflow/propagation/install/validator/methods.js +60 -51
  30. package/lib/dataflow/sinks/index.js +15 -2
  31. package/lib/dataflow/sinks/install/child-process.js +224 -0
  32. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +47 -23
  33. package/lib/dataflow/sinks/install/fs.js +136 -0
  34. package/lib/dataflow/sinks/install/http.js +48 -32
  35. package/lib/dataflow/sinks/install/koa/index.js +30 -0
  36. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +122 -0
  37. package/lib/dataflow/sinks/install/marsdb.js +135 -0
  38. package/lib/dataflow/sinks/install/mongodb.js +205 -0
  39. package/lib/dataflow/sinks/install/mssql.js +19 -13
  40. package/lib/dataflow/sinks/install/mysql.js +122 -0
  41. package/lib/dataflow/sinks/install/postgres.js +40 -29
  42. package/lib/dataflow/sinks/install/sqlite3.js +99 -0
  43. package/lib/dataflow/sources/handler.js +19 -15
  44. package/lib/dataflow/sources/index.js +9 -0
  45. package/lib/dataflow/sources/install/busboy1.js +112 -0
  46. package/lib/dataflow/sources/install/fastify/fastify.js +23 -29
  47. package/lib/dataflow/sources/install/fastify/index.js +4 -5
  48. package/lib/dataflow/sources/install/formidable1.js +91 -0
  49. package/lib/dataflow/sources/install/http.js +35 -14
  50. package/lib/dataflow/sources/install/koa/index.js +32 -0
  51. package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +92 -0
  52. package/lib/dataflow/sources/install/koa/koa-routers.js +84 -0
  53. package/lib/dataflow/sources/install/koa/koa2.js +103 -0
  54. package/lib/dataflow/sources/install/qs6.js +84 -0
  55. package/lib/dataflow/utils/is-vulnerable.js +1 -1
  56. package/package.json +2 -2
  57. package/lib/dataflow/signatures/index.js +0 -2006
  58. package/lib/dataflow/signatures/mssql.js +0 -49
  59. package/lib/dataflow/sources/install/fastify/cookie.js +0 -61
@@ -0,0 +1,224 @@
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
+ const {
18
+ DataflowTag: { UNTRUSTED }
19
+ } = require('@contrast/common');
20
+
21
+ const { patchType } = require('../common');
22
+ const { Rule, isString, inspect } = require('@contrast/common');
23
+
24
+ module.exports = function (core) {
25
+ const {
26
+ depHooks,
27
+ patcher,
28
+ scopes: { sources },
29
+ assess: {
30
+ dataflow: {
31
+ tracker,
32
+ sinks: { isVulnerable, reportFindings },
33
+ eventFactory: { createSinkEvent },
34
+ },
35
+ },
36
+ } = core;
37
+
38
+ const safeTags = [];
39
+
40
+ function commandCheck(name, command, secondArg, thirdArg, hooked) {
41
+ const strInfo = tracker.getData(command);
42
+ if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) return {
43
+ strInfo: null,
44
+ reported: false
45
+ };
46
+
47
+ const event = createSinkEvent({
48
+ name,
49
+ history: [strInfo],
50
+ object: {
51
+ value: 'child_process',
52
+ tracked: false,
53
+ },
54
+ args: [
55
+ {
56
+ value: strInfo.value,
57
+ tracked: true,
58
+ },
59
+ (secondArg && {
60
+ value: inspect(secondArg),
61
+ tracked: false
62
+ }),
63
+ (thirdArg && {
64
+ value: inspect(thirdArg),
65
+ tracked: false
66
+ })
67
+ ].filter(Boolean),
68
+ tags: strInfo.tags,
69
+ source: 'P0',
70
+ stacktraceOpts: {
71
+ constructorOpt: hooked,
72
+ },
73
+ });
74
+
75
+ if (event) {
76
+ reportFindings({
77
+ ruleId: Rule.CMD_INJECTION,
78
+ sinkEvent: event,
79
+ });
80
+
81
+ return {
82
+ strInfo,
83
+ reported: true
84
+ };
85
+ }
86
+
87
+ return {
88
+ strInfo,
89
+ reported: false
90
+ };
91
+ }
92
+
93
+ function argumentsCheck(name, command, commandInfo, args, options, hooked) {
94
+ if (!Array.isArray(args) || !args?.length) return;
95
+
96
+ const trackedArgs = [];
97
+ let vulnerableArgIdx;
98
+
99
+ for (let i = 0; i < args.length; i++) {
100
+ const trackData = tracker.getData(args[i]);
101
+
102
+ trackedArgs.push(trackData);
103
+
104
+ if (!trackData) {
105
+ continue;
106
+ }
107
+
108
+ if (
109
+ !vulnerableArgIdx &&
110
+ vulnerableArgIdx != 0 &&
111
+ isVulnerable(UNTRUSTED, safeTags, trackData.tags)
112
+ ) {
113
+ vulnerableArgIdx = i;
114
+ }
115
+ }
116
+
117
+ if (vulnerableArgIdx != 0 && !vulnerableArgIdx) return;
118
+
119
+ const event = createSinkEvent({
120
+ name,
121
+ history: [trackedArgs[vulnerableArgIdx]],
122
+ object: {
123
+ value: 'child_process',
124
+ tracked: false,
125
+ },
126
+ args: [
127
+ {
128
+ value: commandInfo?.value || command,
129
+ tracked: !!commandInfo,
130
+ },
131
+ {
132
+ value: inspect(args),
133
+ tracked: true
134
+ },
135
+ {
136
+ value: inspect(options),
137
+ tracked: false
138
+ }
139
+ ],
140
+ tags: trackedArgs[vulnerableArgIdx].tags,
141
+ source: 'P1',
142
+ stacktraceOpts: {
143
+ contructorOpt: hooked,
144
+ },
145
+ });
146
+
147
+ if (event) {
148
+ reportFindings({
149
+ ruleId: Rule.CMD_INJECTION,
150
+ sinkEvent: event,
151
+ });
152
+ }
153
+ }
154
+
155
+ core.assess.dataflow.sinks.cmdInjection = {
156
+ install() {
157
+ depHooks.resolve({ name: 'child_process' }, cp => {
158
+ ['spawn', 'spawnSync'].forEach((method) => {
159
+ const name = `child_process.${method}`;
160
+ patcher.patch(cp, method, {
161
+ name,
162
+ patchType,
163
+ pre(data) {
164
+ const store = sources.getStore()?.assess;
165
+ const [command] = data.args;
166
+
167
+ if (!store || !command || !isString(command)) return;
168
+
169
+ const cpArgs = Array.isArray(data.args[1]) && data.args[1];
170
+ const options = cpArgs ? data.args[2] : data.args[1];
171
+
172
+ const cmdCheck = commandCheck(name, command, cpArgs, options, data.hooked);
173
+
174
+ if (cmdCheck.reported || !options?.shell) return;
175
+
176
+ argumentsCheck(name, command, cmdCheck.strInfo, cpArgs, options, data.hooked);
177
+ }
178
+ });
179
+ });
180
+
181
+ ['exec', 'execSync'].forEach((method) => {
182
+ const name = `child_process.${method}`;
183
+ patcher.patch(cp, method, {
184
+ name,
185
+ patchType,
186
+ pre(data) {
187
+ const store = sources.getStore()?.assess;
188
+ const [command, secondArg, thirdArg] = data.args;
189
+
190
+ if (!store || !command || !isString(command)) return;
191
+
192
+ commandCheck(name, command, secondArg, thirdArg, data.hooked);
193
+ }
194
+ });
195
+ });
196
+
197
+ ['execFile', 'execFileSync'].forEach((method) => {
198
+ const name = `child_process.${method}`;
199
+ patcher.patch(cp, method, {
200
+ name,
201
+ patchType,
202
+ pre(data) {
203
+ const store = sources.getStore()?.assess;
204
+ const [command] = data.args;
205
+
206
+ if (!store || !command || !isString(command)) return;
207
+
208
+ const cpArgs = Array.isArray(data.args[1]) && data.args[1];
209
+ const options = cpArgs ? data.args[2] : data.args[1];
210
+
211
+ if (!options?.shell) return;
212
+
213
+ const cmdInfo = tracker.getData(command);
214
+
215
+ argumentsCheck(name, command, cmdInfo, cpArgs, options, data.hooked);
216
+ }
217
+ });
218
+ });
219
+ });
220
+ },
221
+ };
222
+
223
+ return core.assess.dataflow.sinks.cmdInjection;
224
+ };
@@ -15,9 +15,20 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { isString } = require('@contrast/common');
19
- const { createModuleLabel } = require('../../../propagation/common');
18
+ const util = require('util');
19
+ const {
20
+ DataflowTag: {
21
+ UNTRUSTED,
22
+ CUSTOM_ENCODED,
23
+ CUSTOM_VALIDATED,
24
+ HTML_ENCODED,
25
+ LIMITED_CHARS,
26
+ URL_ENCODED,
27
+ },
28
+ isString
29
+ } = require('@contrast/common');
20
30
  const { patchType } = require('../../common');
31
+ const { createSubsetTags } = require('../../../tag-utils');
21
32
 
22
33
  module.exports = function (core) {
23
34
  const {
@@ -35,14 +46,15 @@ module.exports = function (core) {
35
46
  const unvalidatedRedirect =
36
47
  (core.assess.dataflow.sinks.fastify.unvalidatedRedirect = {});
37
48
 
49
+ const inspect = patcher.unwrap(util.inspect);
50
+
38
51
  const safeTags = [
39
- 'limited-chars',
40
- 'url-encoded',
41
- 'html-encoded',
42
- 'custom-validated',
43
- 'custom-encoded'
52
+ CUSTOM_ENCODED,
53
+ CUSTOM_VALIDATED,
54
+ HTML_ENCODED,
55
+ LIMITED_CHARS,
56
+ URL_ENCODED,
44
57
  ];
45
- const requiredTag = 'untrusted';
46
58
 
47
59
  /**
48
60
  * Patches `Reply.prototype.redirect` for
@@ -67,33 +79,45 @@ module.exports = function (core) {
67
79
  const strInfo = tracker.getData(url);
68
80
  if (!strInfo) return;
69
81
 
70
- if (isVulnerable(requiredTag, safeTags, strInfo.tags)) {
82
+ // todo: how does different tag logic play into display ranges?
83
+
84
+ let urlPathTags = strInfo.tags;
85
+ const urlPathEndIdx = url.indexOf('?');
86
+
87
+ if (urlPathEndIdx > -1) {
88
+ urlPathTags = createSubsetTags(strInfo.tags, 0, urlPathEndIdx);
89
+ }
90
+
91
+ if (isVulnerable(UNTRUSTED, safeTags, urlPathTags)) {
71
92
  const event = createSinkEvent({
72
- name: 'fastify.reply.redirect',
73
- object: {
74
- value: `[${createModuleLabel('fastify', version)}].Reply`,
75
- isTracked: false,
76
- },
77
- history: [strInfo],
78
93
  args: [{
94
+ tracked: true,
79
95
  value: strInfo.value,
80
- isTracked: true
81
96
  }],
97
+ context: `reply.redirect(${inspect(strInfo.value)})`,
98
+ history: [strInfo],
99
+ name: 'fastify.reply.redirect',
100
+ object: {
101
+ tracked: false,
102
+ value: 'fastify.Reply',
103
+ },
82
104
  result: {
83
- value: url,
84
- isTracked: true,
105
+ tracked: false,
106
+ value: undefined,
85
107
  },
86
- tags: strInfo.tags,
108
+ tags: urlPathTags,
87
109
  source: 'P0',
88
110
  stacktraceOpts: {
89
111
  constructorOpt: data.hooked,
90
112
  },
91
113
  });
92
114
 
93
- reportFindings({
94
- ruleId: 'unvalidated-redirect', // add Rule.UNVALIDATED_REDIRECT
95
- metadata: event,
96
- });
115
+ if (event) {
116
+ reportFindings({
117
+ ruleId: 'unvalidated-redirect', // add Rule.UNVALIDATED_REDIRECT
118
+ sinkEvent: event,
119
+ });
120
+ }
97
121
  }
98
122
  },
99
123
  });
@@ -0,0 +1,136 @@
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
+ const { patchType } = require('../common');
18
+ const { FS_METHODS, Rule, isString, DataflowTag: { URL_ENCODED, LIMITED_CHARS, ALPHANUM_SPACE_HYPHEN, SAFE_PATH, UNTRUSTED } } = require('@contrast/common');
19
+
20
+ module.exports = function (core) {
21
+ const {
22
+ depHooks,
23
+ patcher,
24
+ scopes: { sources },
25
+ assess: {
26
+ dataflow: {
27
+ tracker,
28
+ sinks: { isVulnerable, reportFindings },
29
+ eventFactory: { createSinkEvent },
30
+ },
31
+ },
32
+ } = core;
33
+
34
+ const safeTags = [URL_ENCODED, LIMITED_CHARS, ALPHANUM_SPACE_HYPHEN, SAFE_PATH];
35
+
36
+ function getValues(indices, args) {
37
+ return indices.reduce((acc, idx) => {
38
+ const value = args[idx];
39
+ if (value && isString(value)) acc.push(value);
40
+ return acc;
41
+ }, []);
42
+ }
43
+
44
+ const pre = (name, indices) => (data) => {
45
+ const store = sources.getStore()?.assess;
46
+ if (!store) return;
47
+
48
+ const values = getValues(indices, data.args);
49
+ if (!values.length) return;
50
+
51
+ const args = [];
52
+ for (let i = 0; i < values.length; i++) {
53
+ const strInfo = tracker.getData(values[i]);
54
+ args.push({ value: strInfo ? strInfo.value : values[i], isTracked: !!strInfo });
55
+ if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) {
56
+ continue;
57
+ }
58
+
59
+ const event = createSinkEvent({
60
+ name,
61
+ history: [strInfo],
62
+ object: {
63
+ value: 'fs',
64
+ isTracked: false,
65
+ },
66
+ args,
67
+ tags: strInfo.tags,
68
+ source: `P${i}`,
69
+ stacktraceOpts: {
70
+ contructorOpt: data.hooked,
71
+ },
72
+ });
73
+
74
+ if (event) {
75
+ reportFindings({
76
+ ruleId: Rule.PATH_TRAVERSAL,
77
+ sinkEvent: event,
78
+ });
79
+ }
80
+ }
81
+ };
82
+
83
+ core.assess.dataflow.sinks.pathTraversal = {
84
+ install() {
85
+ depHooks.resolve({ name: 'fs' }, (fs) => {
86
+ for (const method of FS_METHODS) {
87
+ // not all methods are available on every OS or Node version.
88
+ if (fs[method.name]) {
89
+ const name = `fs.${method.name}`;
90
+ patcher.patch(fs, method.name, {
91
+ name,
92
+ patchType,
93
+ pre: pre(name, method.indices)
94
+ });
95
+ }
96
+
97
+ if (method.sync) {
98
+ const syncName = `${method.name}Sync`;
99
+ if (fs[syncName]) {
100
+ const name = `fs.${syncName}`;
101
+ patcher.patch(fs, syncName, {
102
+ name,
103
+ patchType,
104
+ pre: pre(name, method.indices)
105
+ });
106
+ }
107
+ }
108
+
109
+ if (method.promises && fs.promises && fs.promises[method.name]) {
110
+ const name = `fs.promises.${method.name}`;
111
+ patcher.patch(fs.promises, method.name, {
112
+ name,
113
+ patchType,
114
+ pre: pre(name, method.indices)
115
+ });
116
+ }
117
+ }
118
+ });
119
+
120
+ depHooks.resolve({ name: 'fs/promises' }, (fsPromises) => {
121
+ for (const method of FS_METHODS) {
122
+ if (method.promises && fsPromises[method.name]) {
123
+ const name = `fsPromises.${method.name}`;
124
+ patcher.patch(fsPromises, method.name, {
125
+ name,
126
+ patchType,
127
+ pre: pre(name, method.indices)
128
+ });
129
+ }
130
+ }
131
+ });
132
+ },
133
+ };
134
+
135
+ return core.assess.dataflow.sinks.pathTraversal;
136
+ };
@@ -15,8 +15,22 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { Rule } = require('@contrast/common');
19
- const { createObjectLabel } = require('../../propagation/common');
18
+ const {
19
+ DataflowTag: {
20
+ UNTRUSTED,
21
+ ALPHANUM_SPACE_HYPHEN,
22
+ COOKIE,
23
+ CUSTOM_ENCODED,
24
+ CUSTOM_VALIDATED,
25
+ HEADER,
26
+ HTML_ENCODED,
27
+ LIMITED_CHARS,
28
+ SQL_ENCODED,
29
+ URL_ENCODED,
30
+ WEAK_URL_ENCODED,
31
+ },
32
+ Rule,
33
+ } = require('@contrast/common');
20
34
  const { patchType } = require('../common');
21
35
 
22
36
  module.exports = function(core) {
@@ -35,20 +49,19 @@ module.exports = function(core) {
35
49
  const http = core.assess.dataflow.sinks.http = {};
36
50
 
37
51
  const safeTags = [
38
- 'alphanum-space-hyphen',
39
- 'cookie',
40
- 'header',
41
- 'limited-chars',
42
- 'html-encoded',
43
- 'sql-encoded',
44
- 'url-encoded',
45
- 'weak-url-encoded',
46
- 'custom-validated',
47
- 'custom-encoded'
52
+ ALPHANUM_SPACE_HYPHEN,
53
+ COOKIE,
54
+ CUSTOM_ENCODED,
55
+ CUSTOM_VALIDATED,
56
+ HEADER,
57
+ HTML_ENCODED,
58
+ LIMITED_CHARS,
59
+ SQL_ENCODED,
60
+ URL_ENCODED,
61
+ WEAK_URL_ENCODED,
48
62
  ];
49
- const requiredTag = 'untrusted';
50
63
 
51
- const preHook = (name) => (data) => {
64
+ const preHook = (name, method) => (data) => {
52
65
  const sourceContext = sources.getStore()?.assess;
53
66
  if (!sourceContext) return;
54
67
 
@@ -61,34 +74,35 @@ module.exports = function(core) {
61
74
  const { contentType } = sourceContext.responseData;
62
75
  if (contentType && isSafeContentType(contentType)) return;
63
76
 
64
- if (isVulnerable(requiredTag, safeTags, strInfo.tags)) {
77
+ if (isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) {
65
78
  const event = createSinkEvent({
66
- ruleId: Rule.REFLECTED_XSS,
67
- name,
68
- history: [strInfo],
69
- object: {
70
- isTracked: false,
71
- value: createObjectLabel('http.ServerResponse')
72
- },
73
79
  args: [{
74
80
  value: strInfo.value,
75
- isTracked: true
81
+ tracked: true
76
82
  }],
83
+ context: `res.${method}(${strInfo.value})`,
84
+ history: [strInfo],
85
+ name,
86
+ object: {
87
+ tracked: false,
88
+ value: 'http.ServerResponse'
89
+ },
77
90
  result: {
78
- value: null,
79
- isTracked: false,
91
+ value: data.result,
92
+ tracked: false,
80
93
  },
81
- tags: strInfo.tags,
94
+ ruleId: Rule.REFLECTED_XSS,
82
95
  source: 'P0',
83
96
  stacktraceOpts: {
84
97
  constructorOpt: data.hooked
85
- }
98
+ },
99
+ tags: strInfo.tags,
86
100
  });
87
101
 
88
102
  if (event) {
89
103
  reportFindings({
90
104
  ruleId: 'reflected-xss',
91
- metadata: event
105
+ sinkEvent: event
92
106
  });
93
107
  }
94
108
  }
@@ -98,18 +112,20 @@ module.exports = function(core) {
98
112
  depHooks.resolve({ name: 'http' }, (http) => {
99
113
  {
100
114
  const name = 'http.ServerResponse.prototype.write';
101
- patcher.patch(http.ServerResponse.prototype, 'write', {
115
+ const method = 'write';
116
+ patcher.patch(http.ServerResponse.prototype, method, {
102
117
  name,
103
118
  patchType,
104
- pre: preHook(name),
119
+ pre: preHook(name, method),
105
120
  });
106
121
  }
107
122
  {
108
123
  const name = 'http.ServerResponse.prototype.end';
109
- patcher.patch(http.ServerResponse.prototype, 'end', {
124
+ const method = 'end';
125
+ patcher.patch(http.ServerResponse.prototype, method, {
110
126
  name,
111
127
  patchType,
112
- pre: preHook(name),
128
+ pre: preHook(name, method),
113
129
  });
114
130
  }
115
131
  });
@@ -0,0 +1,30 @@
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 { callChildComponentMethodsSync } = require('@contrast/common');
19
+
20
+ module.exports = function(core) {
21
+ const koa = core.assess.dataflow.sinks.koa = {};
22
+
23
+ require('./unvalidated-redirect')(core);
24
+
25
+ koa.install = function() {
26
+ callChildComponentMethodsSync(koa, 'install');
27
+ };
28
+
29
+ return koa;
30
+ };