@contrast/assess 1.28.0 → 1.29.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 (81) hide show
  1. package/lib/crypto-analysis/install/crypto.js +3 -3
  2. package/lib/dataflow/propagation/install/JSON/parse-fn.js +5 -5
  3. package/lib/dataflow/propagation/install/JSON/parse.js +3 -3
  4. package/lib/dataflow/propagation/install/JSON/stringify.js +24 -17
  5. package/lib/dataflow/propagation/install/array-prototype-join.js +3 -3
  6. package/lib/dataflow/propagation/install/buffer.js +60 -2
  7. package/lib/dataflow/propagation/install/contrast-methods/add.js +1 -3
  8. package/lib/dataflow/propagation/install/ejs/template.js +3 -3
  9. package/lib/dataflow/propagation/install/joi/boolean.js +1 -1
  10. package/lib/dataflow/propagation/install/joi/expression.js +1 -1
  11. package/lib/dataflow/propagation/install/joi/index.js +1 -1
  12. package/lib/dataflow/propagation/install/joi/keys.js +5 -4
  13. package/lib/dataflow/propagation/install/joi/number.js +1 -1
  14. package/lib/dataflow/propagation/install/joi/string-schema.js +3 -2
  15. package/lib/dataflow/propagation/install/joi/utils.js +9 -5
  16. package/lib/dataflow/propagation/install/joi/values.js +4 -3
  17. package/lib/dataflow/propagation/install/mongoose/schema-map.js +2 -2
  18. package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +2 -2
  19. package/lib/dataflow/propagation/install/mongoose/schema-string.js +2 -2
  20. package/lib/dataflow/propagation/install/path/basename.js +2 -2
  21. package/lib/dataflow/propagation/install/path/common.js +5 -5
  22. package/lib/dataflow/propagation/install/path/format.js +7 -4
  23. package/lib/dataflow/propagation/install/path/join-and-resolve.js +2 -2
  24. package/lib/dataflow/propagation/install/path/parse.js +4 -5
  25. package/lib/dataflow/propagation/install/querystring/escape.js +1 -1
  26. package/lib/dataflow/propagation/install/querystring/parse.js +8 -8
  27. package/lib/dataflow/propagation/install/querystring/stringify.js +1 -1
  28. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +2 -3
  29. package/lib/dataflow/propagation/install/send.js +2 -2
  30. package/lib/dataflow/propagation/install/string/concat.js +19 -19
  31. package/lib/dataflow/propagation/install/string/html-methods.js +1 -1
  32. package/lib/dataflow/propagation/install/string/index.js +4 -3
  33. package/lib/dataflow/propagation/install/string/match-all.js +3 -9
  34. package/lib/dataflow/propagation/install/string/match.js +6 -5
  35. package/lib/dataflow/propagation/install/string/replace.js +23 -17
  36. package/lib/dataflow/propagation/install/string/slice.js +5 -5
  37. package/lib/dataflow/propagation/install/string/split.js +13 -11
  38. package/lib/dataflow/propagation/install/string/substring.js +6 -5
  39. package/lib/dataflow/propagation/install/url/parse.js +1 -1
  40. package/lib/dataflow/propagation/install/url/searchParams.js +2 -1
  41. package/lib/dataflow/propagation/install/url/url.js +1 -1
  42. package/lib/dataflow/sinks/index.js +1 -0
  43. package/lib/dataflow/sinks/install/child-process.js +4 -4
  44. package/lib/dataflow/sinks/install/express/reflected-xss.js +7 -5
  45. package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +1 -2
  46. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +1 -3
  47. package/lib/dataflow/sinks/install/fs.js +3 -3
  48. package/lib/dataflow/sinks/install/function.js +3 -3
  49. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.js +1 -2
  50. package/lib/dataflow/sinks/install/http/request.js +6 -5
  51. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +2 -2
  52. package/lib/dataflow/sinks/install/libxmljs.js +1 -1
  53. package/lib/dataflow/sinks/install/marsdb.js +1 -2
  54. package/lib/dataflow/sinks/install/mongodb.js +1 -1
  55. package/lib/dataflow/sinks/install/mysql.js +1 -1
  56. package/lib/dataflow/sinks/install/postgres.js +1 -3
  57. package/lib/dataflow/sinks/install/restify.js +208 -0
  58. package/lib/dataflow/sinks/install/sequelize.js +1 -2
  59. package/lib/dataflow/sinks/install/vm.js +5 -5
  60. package/lib/dataflow/sources/handler.js +2 -2
  61. package/lib/dataflow/sources/index.js +1 -0
  62. package/lib/dataflow/sources/install/http.js +4 -4
  63. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.js +85 -0
  64. package/lib/dataflow/sources/install/restify/index.js +32 -0
  65. package/lib/dataflow/sources/install/restify/jsonBodyParser.js +109 -0
  66. package/lib/dataflow/sources/install/restify/router.js +77 -0
  67. package/lib/dataflow/tag-utils.js +20 -4
  68. package/lib/dataflow/tracker.js +1 -0
  69. package/lib/event-factory.js +3 -3
  70. package/lib/get-policy.js +2 -2
  71. package/lib/index.d.ts +18 -0
  72. package/lib/index.js +13 -0
  73. package/lib/make-source-context.js +2 -2
  74. package/lib/response-scanning/handlers/index.js +10 -10
  75. package/lib/response-scanning/handlers/utils.js +19 -12
  76. package/lib/response-scanning/install/http.js +9 -59
  77. package/lib/session-configuration/install/express-session.js +3 -5
  78. package/lib/session-configuration/install/fastify-cookie.js +3 -3
  79. package/lib/session-configuration/install/hapi.js +1 -3
  80. package/lib/session-configuration/install/koa.js +1 -1
  81. package/package.json +4 -4
@@ -19,7 +19,7 @@ const {
19
19
  InputType,
20
20
  DataflowTag,
21
21
  isString,
22
- join,
22
+ ArrayPrototypeJoin,
23
23
  } = require('@contrast/common');
24
24
 
25
25
  module.exports = function (core) {
@@ -137,7 +137,7 @@ module.exports = function (core) {
137
137
  }
138
138
 
139
139
  traverse(_data, (path, fieldName, value, obj) => {
140
- const pathName = join(path, '.');
140
+ const pathName = ArrayPrototypeJoin.call(path, '.');
141
141
 
142
142
  if (sourceContext.sourceEventsCount >= max) {
143
143
  logger.trace({ inputType, sourceName: name }, 'exiting assess source handling - %s max events exceeded', max);
@@ -26,6 +26,7 @@ module.exports = function (core) {
26
26
  require('./install/fastify')(core);
27
27
  require('./install/hapi')(core);
28
28
  require('./install/koa')(core);
29
+ require('./install/restify')(core);
29
30
  require('./install/body-parser1')(core);
30
31
  require('./install/busboy')(core);
31
32
  require('./install/cookie-parser1')(core);
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
  const { patchType } = require('../common');
18
- const { toLowerCase, InputType } = require('@contrast/common');
18
+ const { StringPrototypeToLowerCase, InputType } = require('@contrast/common');
19
19
 
20
20
  /**
21
21
  * @param {{
@@ -65,13 +65,13 @@ module.exports = function (core) {
65
65
  const key = obj[i];
66
66
  const value = obj[i + 1];
67
67
 
68
- if (toLowerCase(key) === 'content-type') {
68
+ if (StringPrototypeToLowerCase.call(key) === 'content-type') {
69
69
  store.assess.responseData.contentType = value;
70
70
  }
71
71
  }
72
72
  } else if (typeof obj === 'object') {
73
73
  for (const [key, value] of Object.entries(obj)) {
74
- if (toLowerCase(key) === 'content-type') {
74
+ if (StringPrototypeToLowerCase.call(key) === 'content-type') {
75
75
  store.assess.responseData.contentType = value;
76
76
  }
77
77
  }
@@ -85,7 +85,7 @@ module.exports = function (core) {
85
85
  patchType,
86
86
  pre(data) {
87
87
  const [name = '', value] = data.args;
88
- if (toLowerCase(name) === 'content-type' && scopes.sources.getStore()?.assess && value) {
88
+ if (StringPrototypeToLowerCase.call(name) === 'content-type' && scopes.sources.getStore()?.assess && value) {
89
89
  store.assess.responseData.contentType = value;
90
90
  }
91
91
  }
@@ -0,0 +1,85 @@
1
+ /*
2
+ * Copyright: 2024 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 { InputType: { BODY } } = require('@contrast/common');
19
+ const { InstrumentationType: { SOURCE } } = require('../../../../constants');
20
+ const { patchType } = require('../../common');
21
+
22
+ module.exports = function init(core) {
23
+ const {
24
+ logger,
25
+ depHooks,
26
+ patcher,
27
+ assess: {
28
+ dataflow: { sources },
29
+ getSourceContext,
30
+ },
31
+ } = core;
32
+
33
+ return core.assess.dataflow.sources.restifyInstrumentation.fieldedTextBodyParser = {
34
+ install() {
35
+ depHooks.resolve(
36
+ { name: 'restify', file: 'lib/plugins/fieldedTextBodyParser.js', version: '>=8' },
37
+ (fieldedTextBodyParser) => patcher.patch(fieldedTextBodyParser, {
38
+ name: 'restify.plugins.fieldedTextBodyParser',
39
+ patchType,
40
+ post(data) {
41
+ data.result = patcher.patch(data.result, {
42
+ name: 'restify.plugins.fieldedTextBodyParser.parseFieldedText',
43
+ patchType,
44
+ pre(data) {
45
+ const { args: [req, , next], name, funcKey } = data;
46
+ data.args[2] = function contrastNext(...args) {
47
+ const sourceContext = getSourceContext(SOURCE);
48
+
49
+ if (!sourceContext) {
50
+ logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
51
+ return next(...args);
52
+ }
53
+
54
+ if (sourceContext.parsedBody) {
55
+ logger.trace({ funcKey }, 'values already tracked');
56
+ return next(...args);
57
+ }
58
+
59
+ try {
60
+ sources.handle({
61
+ context: 'req.body',
62
+ data: req.body,
63
+ inputType: BODY,
64
+ name,
65
+ stacktraceOpts: {
66
+ constructorOpt: contrastNext,
67
+ },
68
+ sourceContext,
69
+ });
70
+
71
+ sourceContext.parsedBody = true;
72
+ } catch (err) {
73
+ logger.error({ err, funcKey }, 'unable to handle Restify source');
74
+ }
75
+
76
+ return next(...args);
77
+ };
78
+ },
79
+ });
80
+ }
81
+ }),
82
+ );
83
+ },
84
+ };
85
+ };
@@ -0,0 +1,32 @@
1
+ /*
2
+ * Copyright: 2024 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 init(core) {
21
+ core.assess.dataflow.sources.restifyInstrumentation = {
22
+ install() {
23
+ callChildComponentMethodsSync(this, 'install');
24
+ },
25
+ };
26
+
27
+ require('./fieldedTextBodyParser')(core);
28
+ require('./jsonBodyParser')(core);
29
+ require('./router')(core);
30
+
31
+ return core.assess.dataflow.sources.restifyInstrumentation;
32
+ };
@@ -0,0 +1,109 @@
1
+ /*
2
+ * Copyright: 2024 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 { InputType: { JSON_VALUE } } = require('@contrast/common');
19
+ const { InstrumentationType: { SOURCE } } = require('../../../../constants');
20
+ const { patchType } = require('../../common');
21
+
22
+ module.exports = function init(core) {
23
+ const {
24
+ logger,
25
+ depHooks,
26
+ patcher,
27
+ assess: {
28
+ dataflow: { sources },
29
+ getSourceContext,
30
+ },
31
+ } = core;
32
+
33
+ return core.assess.dataflow.sources.restifyInstrumentation.jsonBodyParser = {
34
+ install() {
35
+ depHooks.resolve(
36
+ { name: 'restify', file: 'lib/plugins/jsonBodyParser.js', version: '>=8' },
37
+ (jsonBodyParser) => patcher.patch(jsonBodyParser, {
38
+ name: 'restify.plugins.jsonBodyParser',
39
+ patchType,
40
+ post(data) {
41
+ const { args: [opts] } = data;
42
+ const index = data.result.length - 1;
43
+
44
+ data.result[index] = patcher.patch(data.result[index], {
45
+ name: 'restify.plugins.jsonBodyParser.parseJson',
46
+ patchType,
47
+ pre(data) {
48
+ const { args: [req, , next], name, funcKey } = data;
49
+
50
+ data.args[2] = function contrastNext(...args) {
51
+ const sourceContext = getSourceContext(SOURCE);
52
+
53
+ if (!sourceContext) {
54
+ logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
55
+ return next(...args);
56
+ }
57
+
58
+ if (sourceContext.parsedBody) {
59
+ logger.trace({ funcKey }, 'values already tracked');
60
+ return next(...args);
61
+ }
62
+
63
+ try {
64
+ sources.handle({
65
+ context: 'req.body',
66
+ data: req.body,
67
+ inputType: JSON_VALUE,
68
+ name,
69
+ stacktraceOpts: {
70
+ constructorOpt: contrastNext,
71
+ },
72
+ sourceContext,
73
+ });
74
+
75
+ sourceContext.parsedBody = true;
76
+ } catch (err) {
77
+ logger.error({ err, funcKey }, 'unable to handle Restify source');
78
+ }
79
+
80
+ if (opts?.mapParams) {
81
+ // we don't check for parsedParams first since these clobber
82
+ try {
83
+ sources.handle({
84
+ context: 'req.params',
85
+ data: req.params,
86
+ inputType: JSON_VALUE,
87
+ name,
88
+ stacktraceOpts: {
89
+ constructorOpt: contrastNext,
90
+ },
91
+ sourceContext,
92
+ });
93
+
94
+ sourceContext.parsedParams = true;
95
+ } catch (err) {
96
+ logger.error({ err, funcKey }, 'unable to handle Restify source');
97
+ }
98
+ }
99
+
100
+ return next(...args);
101
+ };
102
+ },
103
+ });
104
+ },
105
+ }),
106
+ );
107
+ },
108
+ };
109
+ };
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright: 2024 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 { InputType: { URL_PARAMETER } } = require('@contrast/common');
19
+ const { InstrumentationType: { SOURCE } } = require('../../../../constants');
20
+ const { patchType } = require('../../common');
21
+
22
+ module.exports = function init(core) {
23
+ const {
24
+ logger,
25
+ depHooks,
26
+ patcher,
27
+ assess: {
28
+ dataflow: { sources },
29
+ getSourceContext,
30
+ },
31
+ } = core;
32
+
33
+ return core.assess.dataflow.sources.restifyInstrumentation.router = {
34
+ install() {
35
+ depHooks.resolve(
36
+ { name: 'restify', file: 'lib/router.js', version: '>=8' },
37
+ (Router) => {
38
+ patcher.patch(Router.prototype, 'lookup', {
39
+ name: 'restify.Router.prototype.lookup',
40
+ patchType,
41
+ post({ args: [req], hooked, orig, name, funcKey }) {
42
+ const sourceContext = getSourceContext(SOURCE);
43
+
44
+ if (!sourceContext) {
45
+ logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
46
+ return;
47
+ }
48
+
49
+ if (sourceContext.parsedParams) {
50
+ logger.trace({ funcKey }, 'values already tracked');
51
+ return;
52
+ }
53
+
54
+ try {
55
+ sources.handle({
56
+ context: 'req.params',
57
+ data: req.params,
58
+ inputType: URL_PARAMETER,
59
+ name,
60
+ stacktraceOpts: {
61
+ constructorOpt: hooked,
62
+ prependFrames: [orig],
63
+ },
64
+ sourceContext,
65
+ });
66
+
67
+ sourceContext.parsedParams = true;
68
+ } catch (err) {
69
+ logger.error({ err, funcKey }, 'unable to handle Restify source');
70
+ }
71
+ },
72
+ });
73
+ },
74
+ );
75
+ },
76
+ };
77
+ };
@@ -14,7 +14,7 @@
14
14
  */
15
15
  'use strict';
16
16
 
17
- const { split } = require('@contrast/common');
17
+ const { StringPrototypeSplit } = require('@contrast/common');
18
18
 
19
19
  //
20
20
  // This module implements tag range manipulation functions. There are generally
@@ -485,8 +485,8 @@ function createAdjustedQueryTags(path, tags, value, argString) {
485
485
  * - "?test=str","%3Ftest%3Dstr",{"UNTRUSTED":[0,8]} => {"UNTRUSTED":[3,6,10,12]}
486
486
  */
487
487
  function createEscapeTagRanges(input, result, tags) {
488
- const inputArr = split(input, '');
489
- const escapedArr = split(result, '');
488
+ const inputArr = StringPrototypeSplit.call(input, '');
489
+ const escapedArr = StringPrototypeSplit.call(result, '');
490
490
  const overlap = inputArr.filter((x) => {
491
491
  if (escapedArr.includes(x)) {
492
492
  return x;
@@ -520,6 +520,21 @@ function createEscapeTagRanges(input, result, tags) {
520
520
  return ret;
521
521
  }
522
522
 
523
+ /**
524
+ * In reporting args, object, and return values, often the exact value isn't important.
525
+ * For untracked values that appear in call contexts it can be enough to just try to
526
+ * report the type of the arg/obj/result.
527
+ * Example: the call
528
+ * http.request('http://tracked-url', { method: 'post' });
529
+ * would have event context string limited to
530
+ * http.request('http://tracked-url,Object);
531
+ *
532
+ * @param {any} origValue value of event result, object, or arg
533
+ * @returns {string} the adjusted value for reporting
534
+ */
535
+ function getAdjustedUntrackedValue(origValue) {
536
+ return origValue?.constructor?.name ?? (origValue === null ? 'null' : typeof origValue);
537
+ }
523
538
 
524
539
  module.exports = {
525
540
  createSubsetTags,
@@ -529,5 +544,6 @@ module.exports = {
529
544
  createTagsWithExclusion,
530
545
  createAdjustedQueryTags,
531
546
  createOverlappingTags,
532
- createEscapeTagRanges
547
+ createEscapeTagRanges,
548
+ getAdjustedUntrackedValue,
533
549
  };
@@ -108,6 +108,7 @@ module.exports = function tracker(core) {
108
108
  }
109
109
 
110
110
  objMap.set(value, metadata);
111
+ metadata.value = value;
111
112
 
112
113
  return metadata;
113
114
  }
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { InputType, match } = require('@contrast/common');
18
+ const { InputType, StringPrototypeMatch } = require('@contrast/common');
19
19
  const ANNOTATION_REGEX = /^(A|O|R|P|P\d+)$/;
20
20
  const SOURCE_EVENT_MSG = 'Source event not created: %s';
21
21
  const PROPAGATION_EVENT_MSG = 'Propagation event not created: %s';
@@ -113,12 +113,12 @@ module.exports = function (core) {
113
113
  return null;
114
114
  }
115
115
 
116
- if (!source || !match(source, ANNOTATION_REGEX)) {
116
+ if (!source || !StringPrototypeMatch.call(source, ANNOTATION_REGEX)) {
117
117
  logger.debug({ name }, PROPAGATION_EVENT_MSG, 'invalid source');
118
118
  return null;
119
119
  }
120
120
 
121
- if (!target || !match(target, ANNOTATION_REGEX)) {
121
+ if (!target || !StringPrototypeMatch.call(target, ANNOTATION_REGEX)) {
122
122
  logger.debug({ name }, PROPAGATION_EVENT_MSG, 'invalid target');
123
123
  return null;
124
124
  }
package/lib/get-policy.js CHANGED
@@ -22,7 +22,7 @@ const {
22
22
  Rule,
23
23
  ResponseScanningRule,
24
24
  SessionConfigurationRule,
25
- join,
25
+ ArrayPrototypeJoin,
26
26
  } = require('@contrast/common');
27
27
 
28
28
  const ASSESS_RULES = Object.values({
@@ -279,7 +279,7 @@ class UrlExclusion {
279
279
  }
280
280
  }
281
281
  if (regexSegments.length) {
282
- this._urlRegex = new RegExp(`^${join(regexSegments, '|')}$`);
282
+ this._urlRegex = new RegExp(`^${ArrayPrototypeJoin.call(regexSegments, '|')}$`);
283
283
  }
284
284
  }
285
285
  }
package/lib/index.d.ts CHANGED
@@ -17,6 +17,20 @@ import {
17
17
  Rule,
18
18
  SessionConfigurationRule,
19
19
  } from '@contrast/common';
20
+ import { Core as _Core } from '@contrast/core';
21
+
22
+ export interface Core extends _Core {
23
+ config: Config;
24
+ logger: Logger;
25
+ depHooks: RequireHook;
26
+ patcher: Patcher
27
+ rewriter: Rewriter;
28
+ scopes: Scopes;
29
+ deadzones: Deadzones;
30
+ reporter: ReporterBus;
31
+ instrumentation: any;
32
+ metrics: any;
33
+ }
20
34
 
21
35
  export enum InstrumentationType {
22
36
  SOURCE = 'source',
@@ -62,3 +76,7 @@ export interface Assess {
62
76
  }
63
77
 
64
78
  export function getSourceContext(instrType?: InstrumentationType, ops?: any): SourceContext;
79
+
80
+ declare function init(core: Core): Assess;
81
+
82
+ export = init;
package/lib/index.js CHANGED
@@ -15,9 +15,12 @@
15
15
 
16
16
  'use strict';
17
17
 
18
+ const { inspect } = require('util');
18
19
  const { callChildComponentMethodsSync } = require('@contrast/common');
19
20
 
20
21
  module.exports = function assess(core) {
22
+ const { scopes: { instrumentation } } = core;
23
+
21
24
  const assess = core.assess = {
22
25
  install() {
23
26
  if (!core.config.getEffectiveValue('assess.enable')) {
@@ -30,6 +33,16 @@ module.exports = function assess(core) {
30
33
  },
31
34
  };
32
35
 
36
+ // todo: this is temporary fix for using inspect during creation of event
37
+ // data. once all uses of inspect are refactored out of remaining sinks and
38
+ // propagators etc, this can also be removed.
39
+ const store = { lock: true, name: 'assess.inspect' };
40
+ assess.inspect = function(val, opts) {
41
+ return instrumentation.isLocked() ?
42
+ inspect(val, opts) :
43
+ instrumentation.run(store, inspect, val, opts);
44
+ };
45
+
33
46
  require('./rule-scopes')(core);
34
47
  require('./get-policy')(core);
35
48
  require('./make-source-context')(core);
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { toLowerCase } = require('@contrast/common');
18
+ const { StringPrototypeToLowerCase } = require('@contrast/common');
19
19
 
20
20
  /**
21
21
  * @param {{
@@ -48,7 +48,7 @@ module.exports = function(core) {
48
48
  // copy to avoid storing tracked values
49
49
  const headers = { ...req.headers };
50
50
  if (headers['content-type']) {
51
- contentType = toLowerCase(headers['content-type']);
51
+ contentType = StringPrototypeToLowerCase.call(headers['content-type']);
52
52
  }
53
53
 
54
54
  return {
@@ -16,9 +16,9 @@
16
16
  'use strict';
17
17
 
18
18
  const {
19
- toLowerCase,
20
- stringify,
21
- substring,
19
+ StringPrototypeToLowerCase,
20
+ JSONStringify,
21
+ StringPrototypeSubstring,
22
22
  ResponseScanningRule
23
23
  } = require('@contrast/common');
24
24
  const {
@@ -130,7 +130,7 @@ module.exports = function(core) {
130
130
  reportFindings(sourceContext, {
131
131
  ruleId: ResponseScanningRule.CACHE_CONTROLS_MISSING,
132
132
  vulnerabilityMetadata: {
133
- data: stringify(instructions)
133
+ data: JSONStringify(instructions)
134
134
  }
135
135
  });
136
136
  }
@@ -144,7 +144,7 @@ module.exports = function(core) {
144
144
  let hasFrameBusting = false;
145
145
 
146
146
  if (xFrameHeaders) {
147
- const xFrameHeadersLC = toLowerCase(xFrameHeaders);
147
+ const xFrameHeadersLC = StringPrototypeToLowerCase.call(xFrameHeaders);
148
148
  hasFrameBusting =
149
149
  xFrameHeadersLC.indexOf('deny') > -1 ||
150
150
  xFrameHeadersLC.indexOf('sameorigin') > -1;
@@ -220,16 +220,16 @@ module.exports = function(core) {
220
220
  let maxAge;
221
221
 
222
222
  if (header) {
223
- header = toLowerCase(header);
223
+ header = StringPrototypeToLowerCase.call(header);
224
224
  const flag = header.indexOf('max-age');
225
225
  if (flag > -1) {
226
226
  const equal = header.indexOf('=', flag);
227
227
  if (equal > -1) {
228
228
  const semicolon = header.indexOf(';', equal);
229
229
  if (semicolon > -1) {
230
- maxAge = substring(header, equal + 1, semicolon);
230
+ maxAge = StringPrototypeSubstring.call(header, equal + 1, semicolon);
231
231
  } else {
232
- maxAge = substring(header, equal + 1);
232
+ maxAge = StringPrototypeSubstring.call(header, equal + 1);
233
233
  }
234
234
  }
235
235
  }
@@ -252,7 +252,7 @@ module.exports = function(core) {
252
252
  let header = responseHeaders[headerName];
253
253
 
254
254
  if (header) {
255
- header = toLowerCase(header);
255
+ header = StringPrototypeToLowerCase.call(header);
256
256
  if (header === 'nosniff') {
257
257
  return;
258
258
  }
@@ -273,7 +273,7 @@ module.exports = function(core) {
273
273
  let header = responseHeaders[headerName];
274
274
 
275
275
  if (header) {
276
- header = toLowerCase(header);
276
+ header = StringPrototypeToLowerCase.call(header);
277
277
 
278
278
  reportFindings(sourceContext, {
279
279
  ruleId: ResponseScanningRule.X_POWERED_BY_HEADER,