@contrast/assess 1.4.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 +1 -0
  20. package/lib/dataflow/propagation/install/string/match.js +3 -3
  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 +35 -14
  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 -2006
  53. package/lib/dataflow/signatures/mssql.js +0 -49
  54. package/lib/dataflow/sources/install/fastify/cookie.js +0 -61
@@ -16,7 +16,7 @@
16
16
  'use strict';
17
17
 
18
18
 
19
- const { InputType } = require('@contrast/common');
19
+ const { InputType, signatures } = require('@contrast/common');
20
20
  const annotationRegExp = /^(A|O|R|P|P\d+)$/;
21
21
 
22
22
  module.exports = function(core) {
@@ -25,10 +25,8 @@ module.exports = function(core) {
25
25
  config,
26
26
  logger,
27
27
  scopes: { sources },
28
- assess: {
29
- dataflow: { signatures }
30
- }
31
28
  } = core;
29
+
32
30
  const eventFactory = core.assess.dataflow.eventFactory = {};
33
31
 
34
32
  eventFactory.createdEvents = new WeakSet();
@@ -36,9 +34,10 @@ module.exports = function(core) {
36
34
  eventFactory.createSourceEvent = function(data = {}) {
37
35
  const {
38
36
  name,
39
- result = { value: null, isTracked: false },
37
+ result = { value: null, tracked: false },
40
38
  tags,
41
39
  inputType,
40
+ stack,
42
41
  } = data;
43
42
 
44
43
  const baseMessage = 'Source event not created: %s';
@@ -63,6 +62,13 @@ module.exports = function(core) {
63
62
  return null;
64
63
  }
65
64
 
65
+
66
+ if (!stack || !Array.isArray(stack)) {
67
+ logger.debug({ data }, baseMessage, 'invalid stack');
68
+ return null;
69
+ }
70
+
71
+ data.time = Date.now();
66
72
  eventFactory.createdEvents.add(data);
67
73
 
68
74
  return data;
@@ -72,9 +78,10 @@ module.exports = function(core) {
72
78
  const {
73
79
  name = '',
74
80
  history = [],
75
- object = { value: null, isTracked: false },
81
+ object = { value: null, tracked: false },
76
82
  args = [],
77
- result = { value: null, isTracked: false },
83
+ context,
84
+ result = { value: null, tracked: false },
78
85
  tags = {},
79
86
  addedTags = [],
80
87
  removedTags = [],
@@ -123,18 +130,19 @@ module.exports = function(core) {
123
130
  }
124
131
 
125
132
  const event = {
126
- time: Date.now(),
133
+ addedTags,
134
+ args,
135
+ context,
127
136
  history,
128
137
  name,
129
138
  object,
130
- args,
131
- result,
132
- tags,
133
- addedTags,
134
139
  removedTags,
140
+ result,
135
141
  source,
142
+ stack,
143
+ tags,
136
144
  target,
137
- stack
145
+ time: Date.now(),
138
146
  };
139
147
 
140
148
  eventFactory.createdEvents.add(event);
@@ -145,24 +153,24 @@ module.exports = function(core) {
145
153
 
146
154
  eventFactory.createSinkEvent = function(data) {
147
155
  const {
156
+ context,
148
157
  name = '',
149
158
  history = [],
150
- object = { value: null, isTracked: false },
159
+ object = { value: null, tracked: false },
151
160
  args = [],
152
- result = { value: null, isTracked: false },
161
+ result = { value: null, tracked: false },
153
162
  tags = {},
154
163
  source,
155
164
  stacktraceOpts
156
165
  } = data;
157
- const sourceContext = sources.getStore()?.assess;
158
166
 
167
+ const sourceContext = sources.getStore()?.assess;
159
168
  if (!sourceContext) {
160
169
  logger.debug('No sourceContext found during Sink event creation');
161
170
  return null;
162
171
  }
163
172
 
164
173
  const signature = signatures.get(name);
165
-
166
174
  if (
167
175
  !signature ||
168
176
  !history.length ||
@@ -174,21 +182,22 @@ module.exports = function(core) {
174
182
 
175
183
  let stack;
176
184
  if (config.assess.stacktraces !== 'NONE') {
177
- stack = createSnapshot(stacktraceOpts);
185
+ stack = createSnapshot(stacktraceOpts)();
178
186
  } else {
179
187
  stack = [];
180
188
  }
181
189
 
182
190
  const event = {
183
- time: Date.now(),
191
+ args,
192
+ context,
184
193
  history,
185
194
  name,
186
195
  object,
187
- args,
188
196
  result,
189
- tags,
190
197
  source,
191
- stack
198
+ stack,
199
+ tags,
200
+ time: Date.now(),
192
201
  };
193
202
 
194
203
  eventFactory.createdEvents.add(event);
@@ -198,59 +207,3 @@ module.exports = function(core) {
198
207
 
199
208
  return eventFactory;
200
209
  };
201
-
202
-
203
- // Sample event data
204
- // const e = {
205
- // // we need the time the event occurred
206
- // time: '1234',
207
- // history: ['argsTrackedInfo'],
208
- // name: 'ContrastMethods.add', // as this method is used to rewrite not only `+` but `+=` too
209
- // context: {
210
- // obj: null,
211
- // args: ['...args'],
212
- // resultTracked: 'result'
213
- // },
214
- // stack: 'createSnapshot()',
215
- // tags: 'newTags',
216
- // // we need a property with add/removed tags
217
- // addedTags: [],
218
- // removedTags: [],
219
- // // we need info for the source and the targeto
220
- // source: 'A | P | O | R',
221
- // target: 'A | P | O | R',
222
- // // optional code property for the propagation through the ContrastMethods
223
- // code: 'const a = b + c',
224
- // // we need a signature property
225
- // signature: {
226
- // // in v4 we are storing all the signatures in a json file,
227
- // // so we get the values from there and format them accordingly
228
- // }
229
- // };
230
-
231
- // Sample payload for a discovered vulnerability
232
- // const payload = {
233
- // created: Date.now(),
234
- // events: [
235
- // {
236
- // action: e.addedTags.length || e.removedTags.length ? 'TAG' : `${e.source}2${e.target}`,
237
- // args: e.context.args, // they will be "expanded" before reporting
238
- // code: e.code,
239
- // eventSources: [], // only for SourceEvents
240
- // fieldName: '', // we don't set it in v4
241
- // object: e.context.obj, // again it will be expanded later
242
- // parentObjectsIds: [], // we don't set it in v4
243
- // properties: [], // not needed for dataflow
244
- // ret: e.context.resultTracked,
245
- // signature: e.signature,
246
- // source: e.source,
247
- // stacktrace: e.stack,
248
- // tags: e.addedTags.join(), // in v4 we set all tags here, idk why
249
- // taintRanges: e.tags.map(), // the tag ranges we want highlighted in ContrastUI
250
- // target: e.target,
251
- // thread: process.pid,
252
- // time: e.time,
253
- // type: e.addedTags.length || e.removedTags.length ? 'TAG' : 'PROPAGATION'
254
- // }
255
- // ]
256
- // };
@@ -20,7 +20,6 @@ const { callChildComponentMethodsSync } = require('@contrast/common');
20
20
  module.exports = function(core) {
21
21
  const dataflow = core.assess.dataflow = {};
22
22
 
23
- require('./signatures')(core);
24
23
  require('./event-factory')(core);
25
24
  require('./tracker')(core);
26
25
  require('./sources')(core);
@@ -83,15 +83,15 @@ module.exports = function(core) {
83
83
  name: 'Array.prototype.join',
84
84
  object: {
85
85
  value: originalJoin.call(obj),
86
- isTracked: false
86
+ tracked: false
87
87
  },
88
88
  result: {
89
89
  value: resultInfo ? resultInfo.value : result,
90
- isTracked: true
90
+ tracked: true
91
91
  },
92
92
  args: [{
93
93
  value: delimiterInfo ? delimiterInfo.value : delimiter,
94
- isTracked: !!delimiterInfo
94
+ tracked: !!delimiterInfo
95
95
  }],
96
96
  tags: newTags,
97
97
  history: Array.from(history),
@@ -15,10 +15,11 @@
15
15
 
16
16
  'use strict';
17
17
 
18
+ const util = require('util');
18
19
  const {
19
20
  createAppendTags
20
21
  } = require('../../../tag-utils');
21
- const { patchType, createObjectLabel } = require('../../common');
22
+ const { patchType } = require('../../common');
22
23
 
23
24
  module.exports = function(core) {
24
25
  const {
@@ -29,13 +30,15 @@ module.exports = function(core) {
29
30
  }
30
31
  } = core;
31
32
 
33
+ const inspect = patcher.unwrap(util.inspect);
34
+
32
35
  return core.assess.dataflow.propagation.contrastMethodsInstrumentation.add = {
33
36
  install() {
34
37
  patcher.patch(global.ContrastMethods, 'add', {
35
38
  name: 'ContrastMethods.add',
36
39
  patchType,
37
40
  post(data) {
38
- const { args, result, hooked, orig } = data;
41
+ const { args, result, hooked } = data;
39
42
  if (!result || !sources.getStore()?.assess || instrumentation.isLocked()) return;
40
43
 
41
44
  const rInfo = tracker.getData(result);
@@ -61,32 +64,36 @@ module.exports = function(core) {
61
64
  }
62
65
 
63
66
  if (history.length) {
67
+ const leftArg = leftStringInfo ? leftStringInfo.value : args[0];
68
+ const rightArg = rightStringInfo ? rightStringInfo.value : args[1];
64
69
  const event = createPropagationEvent({
65
- name: 'ContrastMethods.add',
66
- history,
67
- object: {
68
- value: createObjectLabel('ContrastMethods'),
69
- isTracked: false
70
- },
71
70
  args: [
72
71
  {
73
- value: args[0],
74
- isTracked: !!leftStringInfo
72
+ tracked: !!leftStringInfo,
73
+ value: leftArg
75
74
  },
76
75
  {
77
- value: args[1],
78
- isTracked: !!rightStringInfo
76
+ tracked: !!rightStringInfo,
77
+ value: rightArg,
79
78
  }
80
79
  ],
80
+ context: `${inspect(leftArg)} + ${inspect(rightArg)}`,
81
+ history,
82
+ object: {
83
+ value: 'String Addition',
84
+ tracked: false
85
+ },
86
+ name: 'ContrastMethods.add',
81
87
  result: {
82
88
  value: result,
83
- isTracked: true
89
+ tracked: true
84
90
  },
85
- tags: newTags,
91
+ source: 'P',
86
92
  stacktraceOpts: {
87
93
  constructorOpt: hooked,
88
- prependFrames: [orig]
89
- }
94
+ },
95
+ tags: newTags,
96
+ target: 'R',
90
97
  });
91
98
  const { extern } = tracker.track(result, event);
92
99
 
@@ -48,45 +48,53 @@ module.exports = function (core) {
48
48
  return;
49
49
  }
50
50
 
51
- const [strings, ...args] = data.args;
52
- const argsData = [
53
- strings.map((str) => ({
54
- value: str,
55
- isTracked: false,
56
- })),
57
- ];
58
-
51
+ const [strings, ...expressions] = data.args;
52
+ const args = [];
59
53
  const history = new Set();
60
- args.forEach((arg) => {
61
- const argData = tracker.getData(arg);
62
- argsData.push({
63
- value: argData?.value ?? arg,
64
- isTracked: !!argData,
54
+ let context = '';
55
+
56
+ // interleave hard-coded strings and interpolated expressions
57
+ for (let i = 0; i < strings.length; i++) {
58
+ const str = strings[i];
59
+ args.push({
60
+ tracked: false,
61
+ value: str,
65
62
  });
66
- if (argData) history.add(argData);
67
- });
63
+ context += str;
64
+
65
+ if (i < strings.length - 1) {
66
+ const argData = tracker.getData(expressions[i]);
67
+ if (argData) history.add(argData);
68
+ const value = argData ? argData.value : expressions[i];
69
+ args.push({
70
+ tracked: !!argData,
71
+ value,
72
+ });
73
+ context += `\${expr${i}}`;
74
+ }
75
+ }
68
76
 
69
77
  Object.assign(
70
78
  resultData,
71
79
  createPropagationEvent({
72
- name: 'ContrastMethods.tag',
80
+ args,
81
+ context: `\`${context}\``,
73
82
  history: Array.from(history),
74
83
  object: {
75
- value: 'ContrastMethods@0000',
76
- isTracked: false,
84
+ tracked: false,
85
+ value: 'Template Literal',
77
86
  },
78
- args: argsData,
79
87
  result: {
88
+ tracked: true,
80
89
  value: resultData.value,
81
- isTracked: true,
82
90
  },
83
- tags: resultData.tags,
91
+ name: 'ContrastMethods.tag',
84
92
  source: 'P',
85
93
  target: 'R',
86
94
  stacktraceOpts: {
87
95
  constructorOpt: data.hooked,
88
- prependFrames: [data.orig],
89
96
  },
97
+ tags: resultData.tags,
90
98
  }),
91
99
  );
92
100
  },
@@ -55,13 +55,13 @@ module.exports = function(core) {
55
55
  name: 'global.decodeURIComponent',
56
56
  object: {
57
57
  value: createObjectLabel('global'),
58
- isTracked: false
58
+ tracked: false
59
59
  },
60
60
  result: {
61
61
  value: result,
62
- isTracked: true
62
+ tracked: true
63
63
  },
64
- args: [{ value: argInfo.value, isTracked: true }],
64
+ args: [{ value: argInfo.value, tracked: true }],
65
65
  tags: newTags,
66
66
  history,
67
67
  removedTags: ['url-encoded'],
@@ -54,13 +54,13 @@ module.exports = function(core) {
54
54
  name: 'ejs.utils.escapeXML',
55
55
  object: {
56
56
  value: `[${createModuleLabel('ejs', version)}].utils`,
57
- isTracked: false
57
+ tracked: false
58
58
  },
59
59
  result: {
60
60
  value: resultInfo ? resultInfo.value : result,
61
- isTracked: true
61
+ tracked: true
62
62
  },
63
- args: [{ value: argInfo.value, isTracked: true }],
63
+ args: [{ value: argInfo.value, tracked: true }],
64
64
  tags: newTags,
65
65
  addedTags: ['weak-url-encoded'],
66
66
  history,
@@ -54,13 +54,13 @@ module.exports = function(core) {
54
54
  name: 'global.encodeURIComponent',
55
55
  object: {
56
56
  value: createObjectLabel('global'),
57
- isTracked: false
57
+ tracked: false
58
58
  },
59
59
  result: {
60
60
  value: result,
61
- isTracked: true
61
+ tracked: true
62
62
  },
63
- args: [{ value: argInfo.value, isTracked: true }],
63
+ args: [{ value: argInfo.value, tracked: true }],
64
64
  tags: newTags,
65
65
  history,
66
66
  addedTags: ['url-encoded'],
@@ -54,13 +54,13 @@ module.exports = function(core) {
54
54
  name: 'escape-html',
55
55
  object: {
56
56
  value: createModuleLabel('escape-html', version),
57
- isTracked: false
57
+ tracked: false
58
58
  },
59
59
  result: {
60
60
  value: resultInfo ? resultInfo.value : result,
61
- isTracked: true
61
+ tracked: true
62
62
  },
63
- args: [{ value: argInfo.value, isTracked: true }],
63
+ args: [{ value: argInfo.value, tracked: true }],
64
64
  tags: newTags,
65
65
  history,
66
66
  addedTags: ['html-encoded'],
@@ -52,13 +52,13 @@ module.exports = function(core) {
52
52
  name: 'global.escape',
53
53
  object: {
54
54
  value: createObjectLabel('global'),
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: newTags,
63
63
  history,
64
64
  addedTags: ['weak-url-encoded'],
@@ -54,13 +54,13 @@ module.exports = function(core) {
54
54
  name: 'handlebars.Utils.escapeExpression',
55
55
  object: {
56
56
  value: `[${createModuleLabel('handlebars', version)}].Utils`,
57
- isTracked: false
57
+ tracked: false
58
58
  },
59
59
  result: {
60
60
  value: resultInfo ? resultInfo.value : result,
61
- isTracked: true
61
+ tracked: true
62
62
  },
63
- args: [{ value: argInfo.value, isTracked: true }],
63
+ args: [{ value: argInfo.value, tracked: true }],
64
64
  tags: newTags,
65
65
  addedTags: ['html-encoded'],
66
66
  history,
@@ -49,13 +49,13 @@ module.exports = function(core) {
49
49
  name: eventName,
50
50
  object: {
51
51
  value: objectValue,
52
- isTracked: false
52
+ tracked: false
53
53
  },
54
54
  result: {
55
55
  value: resultInfo ? resultInfo.value : result,
56
- isTracked: true
56
+ tracked: true
57
57
  },
58
- args: [{ value: argInfo.value, isTracked: true }],
58
+ args: [{ value: argInfo.value, tracked: true }],
59
59
  tags: newTags,
60
60
  addedTags: ['sql-encoded'],
61
61
  history,
@@ -54,13 +54,13 @@ module.exports = function(core) {
54
54
  name: 'pug-runtime.escape',
55
55
  object: {
56
56
  value: createModuleLabel('pug-runtime', version),
57
- isTracked: false
57
+ tracked: false
58
58
  },
59
59
  result: {
60
60
  value: resultInfo ? resultInfo.value : result,
61
- isTracked: true
61
+ tracked: true
62
62
  },
63
- args: [{ value: argInfo.value, isTracked: true }],
63
+ args: [{ value: argInfo.value, tracked: true }],
64
64
  tags: newTags,
65
65
  addedTags: ['weak-url-encoded'],
66
66
  history,
@@ -46,18 +46,18 @@ module.exports = function(core) {
46
46
  history: [trackingData],
47
47
  object: {
48
48
  value: part,
49
- isTracked: true,
49
+ tracked: true,
50
50
  },
51
51
  args: data.origArgs.map((arg) => {
52
52
  const argInfo = tracker.getData(arg);
53
53
  return {
54
54
  value: argInfo ? argInfo.value : util.inspect(arg),
55
- isTracked: !!argInfo
55
+ tracked: !!argInfo
56
56
  };
57
57
  }),
58
58
  result: {
59
59
  value: result,
60
- isTracked: !!resultInfo
60
+ tracked: !!resultInfo
61
61
  },
62
62
  tags: tagRanges,
63
63
  stacktraceOpts: {
@@ -57,13 +57,13 @@ module.exports = function(core) {
57
57
  name: 'sql-template-strings.SQL',
58
58
  object: {
59
59
  value: createModuleLabel('sql-template-strings', version),
60
- isTracked: false
60
+ tracked: false
61
61
  },
62
62
  result: {
63
63
  value: resultInfo ? resultInfo.value : resultValue,
64
- isTracked: true
64
+ tracked: true
65
65
  },
66
- args: [{ value: argInfo.value, isTracked: true }],
66
+ args: [{ value: argInfo.value, tracked: true }],
67
67
  tags: newTags,
68
68
  addedTags: ['sql-encoded'],
69
69
  history,
@@ -62,10 +62,10 @@ module.exports = function(core) {
62
62
 
63
63
  argsData.push({
64
64
  value: strInfo?.value ?? str,
65
- isTracked: !!strInfo
65
+ tracked: !!strInfo
66
66
  });
67
67
 
68
- globalOffset += str.length;
68
+ globalOffset += `${str}`.length;
69
69
  }
70
70
 
71
71
  if (history.size) {
@@ -73,11 +73,11 @@ module.exports = function(core) {
73
73
  name: 'String.prototype.concat',
74
74
  object: {
75
75
  value: objInfo?.value || String(obj),
76
- isTracked: !!objInfo
76
+ tracked: !!objInfo
77
77
  },
78
78
  result: {
79
79
  value: result,
80
- isTracked: true
80
+ tracked: true
81
81
  },
82
82
  args: argsData,
83
83
  tags: newTags,
@@ -46,11 +46,11 @@ module.exports = function(core) {
46
46
  name: `String.prototype.${method}`,
47
47
  object: {
48
48
  value: objInfo.value,
49
- isTracked: true
49
+ tracked: true
50
50
  },
51
51
  result: {
52
52
  value: result,
53
- isTracked: true
53
+ tracked: true
54
54
  },
55
55
  args: [],
56
56
  tags: objInfo.tags,
@@ -78,14 +78,14 @@ module.exports = function(core) {
78
78
  name: 'String.prototype.anchor',
79
79
  object: {
80
80
  value: objInfo?.value || String(obj),
81
- isTracked: !!objInfo
81
+ tracked: !!objInfo
82
82
  },
83
83
  result: {
84
84
  value: result,
85
- isTracked: true
85
+ tracked: true
86
86
  },
87
87
  args: [
88
- { value: arg, isTracked: !!argInfo }
88
+ { value: arg, tracked: !!argInfo }
89
89
  ],
90
90
  tags: adjustTags('anchor', objInfo?.tags, `${arg}`.length, argInfo?.tags),
91
91
  history: Array.from(history),
@@ -126,11 +126,11 @@ module.exports = function(core) {
126
126
  name: `String.prototype.${method}`,
127
127
  object: {
128
128
  value: objInfo.value,
129
- isTracked: true
129
+ tracked: true
130
130
  },
131
131
  result: {
132
132
  value: result,
133
- isTracked: true
133
+ tracked: true
134
134
  },
135
135
  args: [],
136
136
  tags: adjustTags(method, objInfo.tags),
@@ -33,6 +33,7 @@ module.exports = function(core) {
33
33
  require('./match')(core);
34
34
  require('./replace')(core);
35
35
  require('./split')(core);
36
+ require('./slice')(core);
36
37
  require('./substring')(core);
37
38
  require('./trim')(core);
38
39