@contrast/assess 1.3.0 → 1.5.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 (54) hide show
  1. package/lib/dataflow/event-factory.js +31 -78
  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 +3 -3
  7. package/lib/dataflow/propagation/install/ejs/escape-xml.js +3 -3
  8. package/lib/dataflow/propagation/install/encode-uri-component.js +3 -3
  9. package/lib/dataflow/propagation/install/escape-html.js +3 -3
  10. package/lib/dataflow/propagation/install/escape.js +3 -3
  11. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +3 -3
  12. package/lib/dataflow/propagation/install/mysql-connection-escape.js +3 -3
  13. package/lib/dataflow/propagation/install/pug-runtime-escape.js +3 -3
  14. package/lib/dataflow/propagation/install/querystring/parse.js +3 -3
  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 +5 -3
  20. package/lib/dataflow/propagation/install/string/match.js +122 -0
  21. package/lib/dataflow/propagation/install/string/replace.js +4 -4
  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 +3 -3
  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/sinks/index.js +11 -2
  30. package/lib/dataflow/sinks/install/child-process.js +87 -0
  31. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +29 -16
  32. package/lib/dataflow/sinks/install/http.js +21 -19
  33. package/lib/dataflow/sinks/install/koa/index.js +30 -0
  34. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +113 -0
  35. package/lib/dataflow/sinks/install/mssql.js +8 -6
  36. package/lib/dataflow/sinks/install/postgres.js +27 -17
  37. package/lib/dataflow/sinks/install/sqlite3.js +94 -0
  38. package/lib/dataflow/sources/handler.js +9 -6
  39. package/lib/dataflow/sources/index.js +9 -0
  40. package/lib/dataflow/sources/install/busboy1.js +112 -0
  41. package/lib/dataflow/sources/install/fastify/fastify.js +23 -29
  42. package/lib/dataflow/sources/install/fastify/index.js +4 -5
  43. package/lib/dataflow/sources/install/formidable1.js +91 -0
  44. package/lib/dataflow/sources/install/http.js +40 -47
  45. package/lib/dataflow/sources/install/koa/index.js +32 -0
  46. package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +92 -0
  47. package/lib/dataflow/sources/install/koa/koa-routers.js +84 -0
  48. package/lib/dataflow/sources/install/koa/koa2.js +103 -0
  49. package/lib/dataflow/sources/install/qs6.js +84 -0
  50. package/lib/dataflow/utils/is-vulnerable.js +1 -1
  51. package/package.json +2 -2
  52. package/lib/dataflow/signatures/index.js +0 -1996
  53. package/lib/dataflow/signatures/mssql.js +0 -49
  54. package/lib/dataflow/sources/install/fastify/cookie.js +0 -61
@@ -0,0 +1,122 @@
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 { join } = 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
+ dataflow: { tracker, eventFactory: { createPropagationEvent } }
27
+ }
28
+ } = core;
29
+
30
+ function getPropagationEvent(data, res, objInfo, start) {
31
+ const { name, args, result, hooked, orig } = data;
32
+ const tags = createSubsetTags(objInfo.tags, start, res.length - 1);
33
+ if (!tags) return;
34
+
35
+ return createPropagationEvent({
36
+ name,
37
+ history: [objInfo],
38
+ object: {
39
+ value: objInfo.value,
40
+ tracked: true,
41
+ },
42
+ args: args.map((arg) => {
43
+ const argInfo = tracker.getData(arg);
44
+ return {
45
+ value: argInfo ? argInfo.value : arg.toString(),
46
+ tracked: !!argInfo
47
+ };
48
+ }),
49
+ tags,
50
+ result: {
51
+ value: join(result),
52
+ tracked: false
53
+ },
54
+ stacktraceOpts: {
55
+ constructorOpt: hooked,
56
+ prependFrames: [orig]
57
+ },
58
+ source: 'O',
59
+ target: 'R'
60
+ });
61
+ }
62
+
63
+ return core.assess.dataflow.propagation.stringInstrumentation.match = {
64
+ install() {
65
+ const name = 'String.prototype.match';
66
+
67
+ patcher.patch(String.prototype, 'match', {
68
+ name,
69
+ patchType,
70
+ post(data) {
71
+ const { args, obj, result } = data;
72
+ if (
73
+ !obj ||
74
+ !result ||
75
+ args.length === 0 ||
76
+ result.length === 0 ||
77
+ !sources.getStore() ||
78
+ typeof obj !== 'string' ||
79
+ instrumentation.isLocked() ||
80
+ (args.length === 1 && args[0] == null)
81
+ ) return;
82
+
83
+ const objInfo = tracker.getData(obj);
84
+ if (!objInfo) return;
85
+
86
+ let idx = 0;
87
+ const hasCaptureGroups = 'groups' in result;
88
+ for (let i = 0; i < result.length; i++) {
89
+ const res = result[i];
90
+ if (!res) continue;
91
+ const start = obj.indexOf(res, idx);
92
+ idx += hasCaptureGroups ? 0 : res.length;
93
+ const event = getPropagationEvent(data, res, objInfo, start);
94
+ if (event) {
95
+ const { extern } = tracker.track(res, event);
96
+ if (extern) {
97
+ data.result[i] = extern;
98
+ }
99
+ }
100
+ }
101
+ if (hasCaptureGroups && result.groups) {
102
+ Object.keys(result.groups).forEach((key) => {
103
+ const res = result.groups[key];
104
+ if (!res) return;
105
+ const start = obj.indexOf(res);
106
+ const event = getPropagationEvent(data, res, objInfo, start);
107
+ if (event) {
108
+ const { extern } = tracker.track(res, event);
109
+ if (extern) {
110
+ data.result.groups[key] = extern;
111
+ }
112
+ }
113
+ });
114
+ }
115
+ },
116
+ });
117
+ },
118
+ uninstall() {
119
+ String.prototype.match = patcher.unwrap(String.prototype.match);
120
+ },
121
+ };
122
+ };
@@ -158,19 +158,19 @@ module.exports = function(core) {
158
158
  history: Array.from(data._history),
159
159
  object: {
160
160
  value: obj,
161
- isTracked: !!data._objInfo
161
+ tracked: !!data._objInfo
162
162
  },
163
163
  args: [{
164
164
  value: args[0].toString(),
165
- isTracked: !!tracker.getData(args[0])
165
+ tracked: !!tracker.getData(args[0])
166
166
  },
167
167
  {
168
168
  value: data._replacement,
169
- isTracked: !!_replacementInfo
169
+ tracked: !!_replacementInfo
170
170
  }],
171
171
  result: {
172
172
  value: result,
173
- isTracked: true
173
+ tracked: true
174
174
  },
175
175
  tags: data._accumTags,
176
176
  stacktraceOpts: {
@@ -0,0 +1,104 @@
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
+ 'use strict';
16
+ const { patchType } = require('../../common');
17
+ const { createSubsetTags } = require('../../../tag-utils');
18
+
19
+ module.exports = function(core) {
20
+ const {
21
+ scopes: { sources, instrumentation },
22
+ patcher,
23
+ assess: {
24
+ dataflow: { tracker, eventFactory: { createPropagationEvent } }
25
+ }
26
+ } = core;
27
+
28
+ function calculateSubsetRangeForSlice({ obj, args }) {
29
+ let [start, end] = args;
30
+ const hasSingleArg = end === undefined;
31
+
32
+ if (start < 0 && hasSingleArg || start < 0 && end < 0) {
33
+ start = obj.length - Math.abs(start);
34
+ end = obj.length - (Math.abs(end) || 0);
35
+ } else if (start > 0 && end < 0) {
36
+ end = obj.length - (Math.abs(end) || 0);
37
+ }
38
+
39
+ const subsetLen = (hasSingleArg ? obj.length - start : Math.abs(end - start)) - 1;
40
+
41
+ return {
42
+ startIdx: start,
43
+ subsetLen
44
+ };
45
+ }
46
+
47
+ return core.assess.dataflow.propagation.stringInstrumentation.slice = {
48
+ install() {
49
+ const name = 'String.prototype.slice';
50
+
51
+ patcher.patch(String.prototype, 'slice', {
52
+ name,
53
+ patchType,
54
+ post(data) {
55
+ const { name, args, obj, result, hooked, orig } = data;
56
+ if (!result || !sources.getStore() || instrumentation.isLocked()) return;
57
+
58
+ const objInfo = tracker.getData(obj);
59
+ if (!objInfo) return;
60
+
61
+ const rInfo = tracker.getData(result);
62
+ if (rInfo) {
63
+ // this may happen w/ trackedStr.slice(0) => trackedStr
64
+ return;
65
+ }
66
+
67
+ const { startIdx, subsetLen } = calculateSubsetRangeForSlice(data);
68
+ const tags = createSubsetTags(objInfo.tags, startIdx, subsetLen);
69
+ if (!tags) return;
70
+
71
+ const event = createPropagationEvent({
72
+ name,
73
+ history: [objInfo],
74
+ object: {
75
+ value: obj,
76
+ tracked: true,
77
+ },
78
+ args: args.map((arg) => ({
79
+ value: arg.toString(),
80
+ tracked: false
81
+ })),
82
+ result: {
83
+ value: result,
84
+ tracked: true
85
+ },
86
+ tags,
87
+ stacktraceOpts: {
88
+ constructorOpt: hooked,
89
+ prependFrames: [orig]
90
+ }
91
+ });
92
+ const { extern } = tracker.track(result, event);
93
+
94
+ if (extern) {
95
+ data.result = extern;
96
+ }
97
+ },
98
+ });
99
+ },
100
+ uninstall() {
101
+ String.prototype.slice = patcher.unwrap(String.prototype.slice);
102
+ },
103
+ };
104
+ };
@@ -50,7 +50,7 @@ module.exports = function(core) {
50
50
  ) return;
51
51
 
52
52
  const objInfo = tracker.getData(obj);
53
- if (!objInfo) return;
53
+ if (!objInfo || obj === result[0]) return;
54
54
 
55
55
  let idx = 0;
56
56
  for (let i = 0; i < result.length; i++) {
@@ -68,19 +68,19 @@ module.exports = function(core) {
68
68
  history: [objInfo],
69
69
  object: {
70
70
  value: obj,
71
- isTracked: true,
71
+ tracked: true,
72
72
  },
73
73
  args: args.map((arg) => {
74
74
  const argInfo = tracker.getData(arg);
75
75
  return {
76
76
  value: argInfo ? argInfo.value : arg.toString(),
77
- isTracked: !!argInfo
77
+ tracked: !!argInfo
78
78
  };
79
79
  }),
80
80
  tags,
81
81
  result: {
82
82
  value: join(result),
83
- isTracked: false
83
+ tracked: false
84
84
  },
85
85
  stacktraceOpts: {
86
86
  constructorOpt: hooked,
@@ -83,21 +83,23 @@ module.exports = function(core) {
83
83
  history: [objInfo],
84
84
  object: {
85
85
  value: obj,
86
- isTracked: true,
86
+ tracked: true,
87
87
  },
88
88
  args: args.map((arg) => ({
89
89
  value: arg.toString(),
90
- isTracked: false
90
+ tracked: false
91
91
  })),
92
92
  result: {
93
93
  value: result,
94
- isTracked: true
94
+ tracked: true
95
95
  },
96
96
  tags,
97
+ source: 'O',
97
98
  stacktraceOpts: {
98
99
  constructorOpt: hooked,
99
100
  prependFrames: [orig]
100
- }
101
+ },
102
+ target: 'R',
101
103
  });
102
104
  const { extern } = tracker.track(result, event);
103
105
 
@@ -63,11 +63,11 @@ module.exports = function(core) {
63
63
  history,
64
64
  object: {
65
65
  value: obj,
66
- isTracked: true
66
+ tracked: true
67
67
  },
68
68
  result: {
69
69
  value: result,
70
- isTracked: true
70
+ tracked: true
71
71
  },
72
72
  tags: newTags,
73
73
  stacktraceOpts: {
@@ -53,13 +53,13 @@ module.exports = function(core) {
53
53
  name: 'global.unescape',
54
54
  object: {
55
55
  value: createObjectLabel('global'),
56
- isTracked: false
56
+ tracked: false
57
57
  },
58
58
  result: {
59
59
  value: resultInfo ? resultInfo.value : result,
60
- isTracked: true
60
+ tracked: true
61
61
  },
62
- args: [{ value: argInfo.value, isTracked: true }],
62
+ args: [{ value: argInfo.value, tracked: true }],
63
63
  tags: newTags,
64
64
  history,
65
65
  removedTags: ['weak-url-encoded'],
@@ -52,13 +52,13 @@ module.exports = function(core) {
52
52
  name: `url.${method}`,
53
53
  object: {
54
54
  value: createModuleLabel('url', version),
55
- isTracked: false
55
+ tracked: false
56
56
  },
57
57
  result: {
58
58
  value: resultInfo ? resultInfo.value : result,
59
- isTracked: true
59
+ tracked: true
60
60
  },
61
- args: [{ value: argInfo.value, isTracked: true }],
61
+ args: [{ value: argInfo.value, tracked: true }],
62
62
  tags: createFullLengthCopyTags(argInfo.tags, result.length) || [],
63
63
  history,
64
64
  source: 'P',
@@ -33,11 +33,11 @@ module.exports = function(core) {
33
33
  history: [{ ...trackingData }],
34
34
  args: [{
35
35
  value: data.args[0],
36
- isTracked: true
36
+ tracked: true
37
37
  }],
38
38
  result: {
39
39
  value: data.result,
40
- isTracked: !!tracker.getData(data.result)
40
+ tracked: !!tracker.getData(data.result)
41
41
  },
42
42
  tags: {
43
43
  ...trackingData.tags,
@@ -21,21 +21,30 @@ const { isSafeContentType } = require('../utils/is-safe-content-type');
21
21
 
22
22
  module.exports = function (core) {
23
23
  const {
24
- messages
24
+ messages,
25
+ scopes: { sources }
25
26
  } = core;
26
27
 
27
28
  const sinks = core.assess.dataflow.sinks = {
28
29
  isVulnerable,
29
30
  isSafeContentType,
30
31
  reportFindings(data) {
31
- messages.emit(Event.ASSESS_DATAFLOW_FINDING, data);
32
+ const store = sources.getStore();
33
+ // these events need source correlation
34
+ messages.emit(Event.ASSESS_DATAFLOW_FINDING, {
35
+ sourceInfo: store?.sourceInfo,
36
+ ...data
37
+ });
32
38
  },
33
39
  };
34
40
 
35
41
  require('./install/fastify')(core);
42
+ require('./install/koa')(core);
43
+ require('./install/child-process')(core);
36
44
  require('./install/http')(core);
37
45
  require('./install/mssql')(core);
38
46
  require('./install/postgres')(core);
47
+ require('./install/sqlite3')(core);
39
48
 
40
49
  sinks.install = function() {
41
50
  callChildComponentMethodsSync(core.assess.dataflow.sinks, 'install');
@@ -0,0 +1,87 @@
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 { Rule, isString } = 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 pre = (name) => (data) => {
35
+ const store = sources.getStore()?.assess;
36
+ if (!store || !data.args[0] || !isString(data.args[0])) return;
37
+
38
+ const strInfo = tracker.getData(data.args[0]);
39
+ if (!strInfo || !isVulnerable('untrusted', [], strInfo.tags)) {
40
+ return;
41
+ }
42
+
43
+ const event = createSinkEvent({
44
+ name,
45
+ history: [strInfo],
46
+ object: {
47
+ value: 'child_process',
48
+ tracked: false,
49
+ },
50
+ args: [
51
+ {
52
+ value: strInfo.value,
53
+ tracked: true,
54
+ },
55
+ ],
56
+ tags: strInfo.tags,
57
+ source: 'P0',
58
+ stacktraceOpts: {
59
+ contructorOpt: data.hooked,
60
+ },
61
+ });
62
+
63
+ if (event) {
64
+ reportFindings({
65
+ ruleId: Rule.CMD_INJECTION,
66
+ sinkEvent: event,
67
+ });
68
+ }
69
+ };
70
+
71
+ core.assess.dataflow.sinks.cmdInjection = {
72
+ install() {
73
+ depHooks.resolve({ name: 'child_process' }, cp => {
74
+ ['spawn', 'spawnSync', 'exec', 'execSync'].forEach((method) => {
75
+ const name = `child_process.${method}`;
76
+ patcher.patch(cp, method, {
77
+ name,
78
+ patchType,
79
+ pre: pre(name)
80
+ });
81
+ });
82
+ });
83
+ },
84
+ };
85
+
86
+ return core.assess.dataflow.sinks.cmdInjection;
87
+ };
@@ -15,9 +15,10 @@
15
15
 
16
16
  'use strict';
17
17
 
18
+ const util = require('util');
18
19
  const { isString } = require('@contrast/common');
19
- const { createModuleLabel } = require('../../../propagation/common');
20
20
  const { patchType } = require('../../common');
21
+ const { createSubsetTags } = require('../../../tag-utils');
21
22
 
22
23
  module.exports = function (core) {
23
24
  const {
@@ -35,6 +36,8 @@ module.exports = function (core) {
35
36
  const unvalidatedRedirect =
36
37
  (core.assess.dataflow.sinks.fastify.unvalidatedRedirect = {});
37
38
 
39
+ const inspect = patcher.unwrap(util.inspect);
40
+
38
41
  const safeTags = [
39
42
  'limited-chars',
40
43
  'url-encoded',
@@ -67,33 +70,43 @@ module.exports = function (core) {
67
70
  const strInfo = tracker.getData(url);
68
71
  if (!strInfo) return;
69
72
 
70
- if (isVulnerable(requiredTag, safeTags, strInfo.tags)) {
73
+ let urlPathTags = strInfo.tags;
74
+ const urlPathEndIdx = url.indexOf('?');
75
+
76
+ if (urlPathEndIdx > -1) {
77
+ urlPathTags = createSubsetTags(strInfo.tags, 0, urlPathEndIdx);
78
+ }
79
+
80
+ if (isVulnerable(requiredTag, safeTags, urlPathTags)) {
71
81
  const event = createSinkEvent({
72
- name: 'fastify.reply.redirect',
73
- object: {
74
- value: `[${createModuleLabel('fastify', version)}].Reply`,
75
- isTracked: false,
76
- },
77
- history: [strInfo],
78
82
  args: [{
83
+ tracked: true,
79
84
  value: strInfo.value,
80
- isTracked: true
81
85
  }],
86
+ context: `reply.redirect(${inspect(strInfo.value)})`,
87
+ history: [strInfo],
88
+ name: 'fastify.reply.redirect',
89
+ object: {
90
+ tracked: false,
91
+ value: 'fastify.Reply',
92
+ },
82
93
  result: {
83
- value: url,
84
- isTracked: true,
94
+ tracked: false,
95
+ value: undefined,
85
96
  },
86
- tags: strInfo.tags,
97
+ tags: urlPathTags,
87
98
  source: 'P0',
88
99
  stacktraceOpts: {
89
100
  constructorOpt: data.hooked,
90
101
  },
91
102
  });
92
103
 
93
- reportFindings({
94
- ruleId: 'unvalidated-redirect', // add Rule.UNVALIDATED_REDIRECT
95
- metadata: event,
96
- });
104
+ if (event) {
105
+ reportFindings({
106
+ ruleId: 'unvalidated-redirect', // add Rule.UNVALIDATED_REDIRECT
107
+ sinkEvent: event,
108
+ });
109
+ }
97
110
  }
98
111
  },
99
112
  });
@@ -16,7 +16,6 @@
16
16
  'use strict';
17
17
 
18
18
  const { Rule } = require('@contrast/common');
19
- const { createObjectLabel } = require('../../propagation/common');
20
19
  const { patchType } = require('../common');
21
20
 
22
21
  module.exports = function(core) {
@@ -48,7 +47,7 @@ module.exports = function(core) {
48
47
  ];
49
48
  const requiredTag = 'untrusted';
50
49
 
51
- const preHook = (name) => (data) => {
50
+ const preHook = (name, method) => (data) => {
52
51
  const sourceContext = sources.getStore()?.assess;
53
52
  if (!sourceContext) return;
54
53
 
@@ -63,32 +62,33 @@ module.exports = function(core) {
63
62
 
64
63
  if (isVulnerable(requiredTag, safeTags, strInfo.tags)) {
65
64
  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
65
  args: [{
74
66
  value: strInfo.value,
75
- isTracked: true
67
+ tracked: true
76
68
  }],
69
+ context: `res.${method}(${strInfo.value})`,
70
+ history: [strInfo],
71
+ name,
72
+ object: {
73
+ tracked: false,
74
+ value: 'http.ServerResponse'
75
+ },
77
76
  result: {
78
- value: null,
79
- isTracked: false,
77
+ value: data.result,
78
+ tracked: false,
80
79
  },
81
- tags: strInfo.tags,
80
+ ruleId: Rule.REFLECTED_XSS,
82
81
  source: 'P0',
83
82
  stacktraceOpts: {
84
83
  constructorOpt: data.hooked
85
- }
84
+ },
85
+ tags: strInfo.tags,
86
86
  });
87
87
 
88
88
  if (event) {
89
89
  reportFindings({
90
90
  ruleId: 'reflected-xss',
91
- metadata: event
91
+ sinkEvent: event
92
92
  });
93
93
  }
94
94
  }
@@ -98,18 +98,20 @@ module.exports = function(core) {
98
98
  depHooks.resolve({ name: 'http' }, (http) => {
99
99
  {
100
100
  const name = 'http.ServerResponse.prototype.write';
101
- patcher.patch(http.ServerResponse.prototype, 'write', {
101
+ const method = 'write';
102
+ patcher.patch(http.ServerResponse.prototype, method, {
102
103
  name,
103
104
  patchType,
104
- pre: preHook(name),
105
+ pre: preHook(name, method),
105
106
  });
106
107
  }
107
108
  {
108
109
  const name = 'http.ServerResponse.prototype.end';
109
- patcher.patch(http.ServerResponse.prototype, 'end', {
110
+ const method = 'end';
111
+ patcher.patch(http.ServerResponse.prototype, method, {
110
112
  name,
111
113
  patchType,
112
- pre: preHook(name),
114
+ pre: preHook(name, method),
113
115
  });
114
116
  }
115
117
  });