@contrast/protect 1.3.0 → 1.4.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 (43) hide show
  1. package/lib/error-handlers/install/express4.js +2 -3
  2. package/lib/error-handlers/install/fastify3.js +2 -4
  3. package/lib/error-handlers/install/koa2.js +1 -2
  4. package/lib/{cli-rewriter.js → get-source-context.js} +13 -15
  5. package/lib/hardening/constants.js +20 -0
  6. package/lib/hardening/handlers.js +65 -0
  7. package/lib/hardening/index.js +29 -0
  8. package/lib/hardening/install/node-serialize0.js +59 -0
  9. package/lib/index.d.ts +3 -21
  10. package/lib/index.js +4 -0
  11. package/lib/input-analysis/handlers.js +169 -7
  12. package/lib/input-analysis/index.js +4 -0
  13. package/lib/input-analysis/install/body-parser1.js +13 -21
  14. package/lib/input-analysis/install/cookie-parser1.js +13 -15
  15. package/lib/input-analysis/install/express4.js +8 -13
  16. package/lib/input-analysis/install/fastify3.js +4 -5
  17. package/lib/input-analysis/install/formidable1.js +4 -5
  18. package/lib/input-analysis/install/http.js +12 -3
  19. package/lib/input-analysis/install/koa-body5.js +5 -10
  20. package/lib/input-analysis/install/koa-bodyparser4.js +6 -10
  21. package/lib/input-analysis/install/koa2.js +13 -24
  22. package/lib/input-analysis/install/multer1.js +5 -6
  23. package/lib/input-analysis/install/qs6.js +7 -11
  24. package/lib/input-analysis/install/universal-cookie4.js +3 -7
  25. package/lib/input-analysis/ip-analysis.js +76 -0
  26. package/lib/input-analysis/virtual-patches.js +109 -0
  27. package/lib/input-tracing/handlers/index.js +86 -22
  28. package/lib/input-tracing/index.js +10 -4
  29. package/lib/input-tracing/install/child-process.js +13 -7
  30. package/lib/input-tracing/install/eval.js +60 -0
  31. package/lib/input-tracing/install/fs.js +4 -2
  32. package/lib/input-tracing/install/http.js +63 -0
  33. package/lib/input-tracing/install/mongodb.js +20 -20
  34. package/lib/input-tracing/install/mysql.js +3 -2
  35. package/lib/input-tracing/install/postgres.js +5 -4
  36. package/lib/input-tracing/install/sequelize.js +7 -5
  37. package/lib/input-tracing/install/sqlite3.js +6 -4
  38. package/lib/input-tracing/install/vm.js +132 -0
  39. package/lib/make-source-context.js +4 -1
  40. package/lib/semantic-analysis/handlers.js +160 -0
  41. package/lib/semantic-analysis/index.js +38 -0
  42. package/package.json +7 -9
  43. package/lib/utils.js +0 -84
@@ -16,30 +16,17 @@
16
16
  'use strict';
17
17
 
18
18
  const util = require('util');
19
- const { simpleTraverse } = require('../../utils');
19
+ const { BLOCKING_MODES, isString, simpleTraverse } = require('@contrast/common');
20
20
 
21
21
  module.exports = function(core) {
22
22
  const { protect: { agentLib, inputTracing, throwSecurityException } } = core;
23
23
 
24
- /**
25
- * Util for pulling results from context for the particular rule id
26
- * @param {string} ruleId rule id
27
- * @param {object} context async storage data for protect
28
- * @returns {AnalysisResult[]}
29
- */
30
- function getResultsByRuleId(ruleId, context) {
31
- if (context.rules.agentLibRules[ruleId].mode === 'off') {
32
- return;
33
- }
34
- return context.findings.resultsMap[ruleId];
35
- }
36
-
37
24
  function handleFindings(sourceContext, sinkContext, ruleId, result, findings) {
38
25
  result.details.push({ sinkContext, findings });
39
26
 
40
27
  const { mode } = sourceContext.rules.agentLibRules[ruleId];
41
28
 
42
- if (['block', 'block_at_perimeter'].includes(mode)) {
29
+ if (BLOCKING_MODES.includes(mode)) {
43
30
  result.blocked = true;
44
31
  const blockInfo = [mode, ruleId];
45
32
  sourceContext.findings.securityException = blockInfo;
@@ -153,13 +140,87 @@ module.exports = function(core) {
153
140
  };
154
141
 
155
142
  inputTracing.ssjsInjection = function(sourceContext, sinkContext) {
156
- // 'ssjs-injection' NYI
157
- return null;
143
+ const ruleId = 'ssjs-injection';
144
+ let sinkValuesArr = [];
145
+
146
+ const results = getResultsByRuleId(ruleId, sourceContext);
147
+
148
+ if (!results) return;
149
+
150
+ if (isString(sinkContext.value)) {
151
+ sinkValuesArr.push(sinkContext.value);
152
+ } else {
153
+ const strValues = Object.values(sinkContext.value).filter((v) => isString(v) && v.length);
154
+ sinkValuesArr = [...strValues];
155
+ }
156
+
157
+ for (const result of results) {
158
+ let findings = null;
159
+
160
+ for (const v of sinkValuesArr) {
161
+ if (findings) break;
162
+
163
+ const inputIndex = v.indexOf(result.value);
164
+
165
+ if (inputIndex === 0 && v === result.value) {
166
+ findings = {
167
+ startIndex: 0,
168
+ endIndex: result?.value.length - 1,
169
+ boundaryIndex: 0,
170
+ codeString: result.value
171
+ };
172
+ }
173
+
174
+ if (inputIndex > 0) {
175
+ const endIndex = inputIndex + result?.value.length;
176
+ findings = agentLib.checkSsjsInjectionSink(v, inputIndex, endIndex) && {
177
+ startIndex: inputIndex,
178
+ endIndex,
179
+ boundaryIndex: inputIndex,
180
+ codeString: result.value
181
+ };
182
+ }
183
+ }
184
+
185
+ if (findings) {
186
+ handleFindings(sourceContext, sinkContext, ruleId, result, findings);
187
+ }
188
+ }
158
189
  };
159
190
 
191
+ inputTracing.handleReflectedXss = function(sourceContext, sinkContext) {
192
+ const ruleId = 'reflected-xss';
193
+ const results = getResultsByRuleId(ruleId, sourceContext);
194
+
195
+ if (!results) return;
196
+
197
+ for (const result of results) {
198
+ const idx = sinkContext.value.indexOf(result.value);
199
+ const findings = idx !== -1 ? { value: sinkContext.value } : null;
200
+
201
+ if (findings) {
202
+ result.details.push({ sinkContext, findings });
203
+ }
204
+ }
205
+ };
206
+
207
+
160
208
  return inputTracing;
161
209
  };
162
210
 
211
+ /**
212
+ * Util for pulling results from context for the particular rule id
213
+ * @param {string} ruleId rule id
214
+ * @param {object} context async storage data for protect
215
+ * @returns {AnalysisResult[]}
216
+ */
217
+ function getResultsByRuleId(ruleId, context) {
218
+ if (context.rules.agentLibRules[ruleId].mode === 'off') {
219
+ return;
220
+ }
221
+ return context.findings.resultsMap[ruleId];
222
+ }
223
+
163
224
  function handleObjectValue(result, object) {
164
225
  if (typeof object !== 'object') {
165
226
  return null;
@@ -179,7 +240,10 @@ function handleObjectValue(result, object) {
179
240
  obj = obj[value];
180
241
  // does the found object in the query equal the saved object?
181
242
  if (util.isDeepStrictEqual(obj, result.mongoContext.inputToCheck)) {
182
- findings = { key: value };
243
+ const start = JSON.stringify(object).indexOf(value);
244
+ const end = start + value.length;
245
+ const inputBoundaryIndex = 0;
246
+ findings = { start, end, boundaryOverrunIndex: start, inputBoundaryIndex };
183
247
  }
184
248
  }
185
249
  });
@@ -201,10 +265,10 @@ function handleStringValue(result, string) {
201
265
 
202
266
  if (inputIndex === 0 && string === result.value) {
203
267
  findings = {
204
- startIndex: 0,
205
- endIndex: result.value.length - 1,
206
- overrunIndex: 0,
207
- boundaryIndex: 0,
268
+ start: 0,
269
+ end: result.value.length - 1,
270
+ boundaryOverrunIndex: 0,
271
+ inputBoundaryIndex: 0,
208
272
  };
209
273
  }
210
274
 
@@ -30,18 +30,24 @@ module.exports = function(core) {
30
30
  require('./handlers')(core);
31
31
 
32
32
  // load the instrumentation installers
33
- require('./install/fs')(core);
34
33
  require('./install/child-process')(core);
34
+ require('./install/fs')(core);
35
+ require('./install/mongodb')(core);
35
36
  require('./install/mysql')(core);
36
37
  require('./install/postgres')(core);
37
- require('./install/mongodb')(core);
38
+ require('./install/sequelize')(core);
39
+ require('./install/sqlite3')(core);
40
+ require('./install/http')(core);
38
41
 
39
42
  inputTracing.install = function() {
40
- inputTracing.fsInstrumentation.install();
41
43
  inputTracing.cpInstrumentation.install();
44
+ inputTracing.fsInstrumentation.install();
45
+ inputTracing.mongodbInstrumentation.install();
42
46
  inputTracing.mysqlInstrumentation.install();
43
47
  inputTracing.postgresInstrumentation.install();
44
- inputTracing.mongodbInstrumentation.install();
48
+ inputTracing.sequelizeInstrumentation.install();
49
+ inputTracing.sqlite3Instrumentation.install();
50
+ inputTracing.httpInstrumentation.install();
45
51
  // TODO: NODE-2360 (2260?)
46
52
  };
47
53
 
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
20
20
 
21
21
  module.exports = function(core) {
22
22
  const {
23
- scopes: { sources, instrumentation },
23
+ scopes: { instrumentation },
24
24
  patcher,
25
25
  depHooks,
26
26
  captureStacktrace,
27
+ protect,
27
28
  protect: { inputTracing }
28
29
  } = core;
29
30
 
@@ -34,20 +35,25 @@ module.exports = function(core) {
34
35
  patcher.patch(cp, method, {
35
36
  name,
36
37
  patchType,
37
- pre(data) {
38
+ pre({ args, hooked, orig }) {
38
39
  if (instrumentation.isLocked()) return;
39
40
 
40
- const sourceContext = sources.getStore()?.protect;
41
- if (!sourceContext) return;
41
+ const sourceContext = protect.getSourceContext('child_process');
42
+ const value = args[0];
42
43
 
43
- const value = data.args[0];
44
- if (!value || !isString(value)) return;
44
+ if (!sourceContext || !value || !isString(value)) return;
45
45
 
46
46
  const sinkContext = captureStacktrace(
47
47
  { name, value },
48
- { constructorOpt: data.hooked, prependFrames: [data.orig] }
48
+ { constructorOpt: hooked, prependFrames: [orig] }
49
49
  );
50
+
50
51
  inputTracing.handleCommandInjection(sourceContext, sinkContext);
52
+ // To evade code duplication we are using these INPUT TRACING instrumentation
53
+ // to do the checks for SEMANTIC ANALYSIS too
54
+ core.protect.semanticAnalysis.handleCommandInjectionCommandBackdoors(sourceContext, sinkContext);
55
+ core.protect.semanticAnalysis.handleCmdInjectionSemanticChainedCommands(sourceContext, sinkContext);
56
+ core.protect.semanticAnalysis.handleCmdInjectionSemanticDangerous(sourceContext, sinkContext);
51
57
  }
52
58
  });
53
59
  });
@@ -0,0 +1,60 @@
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 { isString } = require('@contrast/common');
19
+ const { patchType } = require('../constants');
20
+
21
+ module.exports = function(core) {
22
+ const {
23
+ logger,
24
+ scopes: { instrumentation },
25
+ patcher,
26
+ captureStacktrace,
27
+ protect,
28
+ protect: { inputTracing }
29
+ } = core;
30
+
31
+ function install() {
32
+ if (!global.ContrastMethods.__contrastEval) {
33
+ logger.error('Cannot install `eval` instrumentation - Contrast method DNE');
34
+ return;
35
+ }
36
+
37
+ patcher.patch(global.ContrastMethods, '__contrastEval', {
38
+ name: 'global.ContrastMethods.__contrastEval',
39
+ patchType,
40
+ pre: ({ args, hooked, orig }) => {
41
+ if (instrumentation.isLocked()) return;
42
+
43
+ const sourceContext = protect.getSourceContext('eval');
44
+ const value = args[0];
45
+
46
+ if (!sourceContext || !value || !isString(value)) return;
47
+
48
+ const sinkContext = captureStacktrace(
49
+ { name: 'eval', value },
50
+ { constructorOpt: hooked, prependFrames: [orig] }
51
+ );
52
+ inputTracing.ssjsInjection(sourceContext, sinkContext);
53
+ }
54
+ });
55
+ }
56
+
57
+ const evalInstrumentation = inputTracing.evalInstrumentation = { install };
58
+
59
+ return evalInstrumentation;
60
+ };
@@ -61,10 +61,11 @@ const fsMethods = [
61
61
 
62
62
  module.exports = function(core) {
63
63
  const {
64
- scopes: { sources, instrumentation },
64
+ scopes: { instrumentation },
65
65
  patcher,
66
66
  depHooks,
67
67
  captureStacktrace,
68
+ protect,
68
69
  protect: { inputTracing }
69
70
  } = core;
70
71
 
@@ -88,7 +89,8 @@ module.exports = function(core) {
88
89
  if (instrumentation.isLocked()) return;
89
90
 
90
91
  // obtain the Protect sourceContext
91
- const sourceContext = sources.getStore()?.protect;
92
+ const sourceContext = protect.getSourceContext('fs');
93
+
92
94
  if (!sourceContext) return;
93
95
 
94
96
  // build list of values on which to perform INPUT TRACING
@@ -0,0 +1,63 @@
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 { patchType } = require('../constants');
19
+
20
+ module.exports = function(core) {
21
+ const {
22
+ scopes: { instrumentation },
23
+ patcher,
24
+ depHooks,
25
+ captureStacktrace,
26
+ protect,
27
+ protect: { inputTracing }
28
+ } = core;
29
+
30
+ function install() {
31
+ depHooks.resolve({ name: 'http' }, http => {
32
+ for (const method of ['write', 'end']) {
33
+ const name = `http.ServerResponse.prototype.${method}`;
34
+ patcher.patch(http.ServerResponse.prototype, method, {
35
+ name,
36
+ patchType,
37
+ pre(data) {
38
+ if (instrumentation.isLocked()) return;
39
+
40
+ const sourceContext = protect.getSourceContext(name);
41
+
42
+ if (!sourceContext) return;
43
+
44
+ const value = data.args[0]?.toString();
45
+ if (!value) return;
46
+
47
+ const sinkContext = captureStacktrace(
48
+ { name, value },
49
+ { constructorOpt: data.hooked }
50
+ );
51
+ inputTracing.handleReflectedXss(sourceContext, sinkContext);
52
+ }
53
+ });
54
+ }
55
+ });
56
+ }
57
+
58
+ const httpInstrumentation = inputTracing.httpInstrumentation = {
59
+ install
60
+ };
61
+
62
+ return httpInstrumentation;
63
+ };
@@ -22,8 +22,8 @@ module.exports = function (core) {
22
22
  const {
23
23
  depHooks,
24
24
  patcher,
25
- scopes: { sources },
26
25
  captureStacktrace,
26
+ protect,
27
27
  protect: { inputTracing },
28
28
  } = core;
29
29
 
@@ -61,15 +61,15 @@ module.exports = function (core) {
61
61
  patcher.patch(obj, method, {
62
62
  name: patchName,
63
63
  patchType,
64
- pre: ({ args, hooked, name }) => {
64
+ pre: ({ args, hooked, name, orig }) => {
65
65
  const value = getCursorQueryData(args, version);
66
- const sourceContext = sources.getStore()?.protect;
66
+ const sourceContext = protect.getSourceContext(patchName);
67
67
 
68
68
  if (!sourceContext || !value) return;
69
69
 
70
70
  const sinkContext = captureStacktrace(
71
71
  { name, value },
72
- { constructorOpt: hooked }
72
+ { constructorOpt: hooked, prependFrames: [orig] }
73
73
  );
74
74
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
75
75
  }
@@ -80,10 +80,10 @@ module.exports = function (core) {
80
80
  patcher.patch(obj, method, {
81
81
  name: patchName,
82
82
  patchType,
83
- pre: ({ args, hooked, name }) => {
84
- const sourceContext = sources.getStore()?.protect;
85
- if (!sourceContext) return;
83
+ pre: ({ args, hooked, name, orig }) => {
84
+ const sourceContext = protect.getSourceContext(patchName);
86
85
 
86
+ if (!sourceContext) return;
87
87
 
88
88
  const ops = Array.isArray(args[1])
89
89
  ? args[1]
@@ -93,7 +93,7 @@ module.exports = function (core) {
93
93
  if (value) {
94
94
  const sinkContext = captureStacktrace(
95
95
  { name, value },
96
- { constructorOpt: hooked }
96
+ { constructorOpt: hooked, prependFrames: [orig] }
97
97
  );
98
98
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
99
99
  }
@@ -126,15 +126,15 @@ module.exports = function (core) {
126
126
  patcher.patch(mongodb.Collection.prototype, method, {
127
127
  name: `mongodb.Collection.prototype.${method}`,
128
128
  patchType,
129
- pre: ({ args, hooked, name }) => {
129
+ pre: ({ args, hooked, name, orig }) => {
130
130
  const value = typeof args[0] == 'function' ? null : args[0];
131
- const sourceContext = sources.getStore()?.protect;
131
+ const sourceContext = protect.getSourceContext(`mongodb.Collection.prototype.${method}`);
132
132
 
133
133
  if (!sourceContext || !value) return;
134
134
 
135
135
  const sinkContext = captureStacktrace(
136
136
  { name, value },
137
- { constructorOpt: hooked }
137
+ { constructorOpt: hooked, prependFrames: [orig] }
138
138
  );
139
139
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
140
140
  },
@@ -144,15 +144,15 @@ module.exports = function (core) {
144
144
  patcher.patch(mongodb.Db.prototype, 'command', {
145
145
  name: 'mongodb.Db.prototype.command',
146
146
  patchType,
147
- pre: ({ args, hooked, name }) => {
147
+ pre: ({ args, hooked, name, orig }) => {
148
148
  const value = args[0]?.filter;
149
- const sourceContext = sources.getStore()?.protect;
149
+ const sourceContext = protect.getSourceContext('mongodb.Collection.prototype.command');
150
150
 
151
151
  if (!sourceContext || !value) return;
152
152
 
153
153
  const sinkContext = captureStacktrace(
154
154
  { name, value },
155
- { constructorOpt: hooked }
155
+ { constructorOpt: hooked, prependFrames: [orig] }
156
156
  );
157
157
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
158
158
  }
@@ -168,15 +168,15 @@ module.exports = function (core) {
168
168
  patcher.patch(mongodb.Db.prototype, 'eval', {
169
169
  name: 'mongodb.Db.prototype.eval',
170
170
  patchType,
171
- pre: ({ args, hooked, name }) => {
171
+ pre: ({ args, hooked, name, orig }) => {
172
172
  const value = args[0];
173
- const sourceContext = sources.getStore()?.protect;
173
+ const sourceContext = protect.getSourceContext('mongodb.Db.prototype.eval');
174
174
 
175
175
  if (!sourceContext || !value) return;
176
176
 
177
177
  const sinkContext = captureStacktrace(
178
178
  { name, value },
179
- { constructorOpt: hooked }
179
+ { constructorOpt: hooked, prependFrames: [orig] }
180
180
  );
181
181
 
182
182
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
@@ -187,15 +187,15 @@ module.exports = function (core) {
187
187
  depHooks.resolve({ name: 'mongodb', file: 'lib/cursor/find_cursor', version: '>=4.0.0' }, (cursor) => patcher.patch(cursor, 'FindCursor', {
188
188
  name: 'mongodb.FindCursor',
189
189
  patchType,
190
- pre: ({ args, hooked, name }) => {
190
+ pre: ({ args, hooked, name, orig }) => {
191
191
  const value = args[2];
192
- const sourceContext = sources.getStore()?.protect;
192
+ const sourceContext = protect.getSourceContext('mongodb.FindCursor');
193
193
 
194
194
  if (!sourceContext || !value) return;
195
195
 
196
196
  const sinkContext = captureStacktrace(
197
197
  { name, value },
198
- { constructorOpt: hooked }
198
+ { constructorOpt: hooked, prependFrames: [orig] }
199
199
  );
200
200
  inputTracing.nosqlInjectionMongo(sourceContext, sinkContext);
201
201
  }
@@ -23,7 +23,7 @@ module.exports = function(core) {
23
23
  depHooks,
24
24
  patcher,
25
25
  captureStacktrace,
26
- scopes: { sources },
26
+ protect,
27
27
  protect: { inputTracing }
28
28
  } = core;
29
29
 
@@ -49,7 +49,8 @@ module.exports = function(core) {
49
49
  patchType,
50
50
  pre(data) {
51
51
  const { args, hooked, name, orig } = data;
52
- const sourceContext = sources.getStore()?.protect;
52
+ const sourceContext = protect.getSourceContext(name);
53
+
53
54
  if (!sourceContext) return;
54
55
 
55
56
  const value = mysqlInstr.getValueFromArgs(args);
@@ -22,8 +22,8 @@ module.exports = function(core) {
22
22
  const {
23
23
  depHooks,
24
24
  patcher,
25
- scopes: { sources },
26
25
  captureStacktrace,
26
+ protect,
27
27
  protect: { inputTracing }
28
28
  } = core;
29
29
 
@@ -32,8 +32,9 @@ module.exports = function(core) {
32
32
  if (query && isString(query)) return query;
33
33
  }
34
34
 
35
- function preHook({ args, hooked, name }) {
36
- const sourceContext = sources.getStore()?.protect;
35
+ function preHook({ args, hooked, name, orig }) {
36
+ const sourceContext = protect.getSourceContext(name);
37
+
37
38
  if (!sourceContext) return;
38
39
 
39
40
  const value = getQueryFromArgs(args);
@@ -41,7 +42,7 @@ module.exports = function(core) {
41
42
 
42
43
  const sinkContext = captureStacktrace(
43
44
  { name, value },
44
- { constructorOpt: hooked }
45
+ { constructorOpt: hooked, prependFrames: [orig] }
45
46
  );
46
47
 
47
48
  inputTracing.handleSqlInjection(sourceContext, sinkContext);
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
20
20
 
21
21
  module.exports = function(core) {
22
22
  const {
23
- scopes: { sources, instrumentation },
23
+ scopes: { instrumentation },
24
24
  patcher,
25
25
  depHooks,
26
26
  captureStacktrace,
27
+ protect,
27
28
  protect: { inputTracing }
28
29
  } = core;
29
30
 
@@ -38,18 +39,19 @@ module.exports = function(core) {
38
39
  patcher.patch(sequelize.prototype, 'query', {
39
40
  name,
40
41
  patchType,
41
- pre({ args, hooked, name }) {
42
+ pre({ args, hooked, name, orig }) {
42
43
  if (instrumentation.isLocked()) return;
43
44
 
44
- const sourceContext = sources.getStore()?.protect;
45
- if (!sourceContext) return;
45
+ const sourceContext = protect.getSourceContext(name);
46
+
47
+ if (!sourceContext || sourceContext.allowed) return;
46
48
 
47
49
  const value = getQueryFromArgs(args);
48
50
  if (!value) return;
49
51
 
50
52
  const sinkContext = captureStacktrace(
51
53
  { name, value },
52
- { constructorOpt: hooked }
54
+ { constructorOpt: hooked, prependFrames: [orig] }
53
55
  );
54
56
  inputTracing.handleSqlInjection(sourceContext, sinkContext);
55
57
  }
@@ -20,10 +20,11 @@ const { patchType } = require('../constants');
20
20
 
21
21
  module.exports = function(core) {
22
22
  const {
23
- scopes: { sources, instrumentation },
23
+ scopes: { instrumentation },
24
24
  patcher,
25
25
  depHooks,
26
26
  captureStacktrace,
27
+ protect,
27
28
  protect: { inputTracing }
28
29
  } = core;
29
30
 
@@ -34,10 +35,10 @@ module.exports = function(core) {
34
35
  patcher.patch(sqlite3.Database.prototype, method, {
35
36
  name,
36
37
  patchType,
37
- pre({ args, hooked, name }) {
38
+ pre({ args, hooked, name, orig }) {
38
39
  if (instrumentation.isLocked()) return;
39
40
 
40
- const sourceContext = sources.getStore()?.protect;
41
+ const sourceContext = protect.getSourceContext(name);
41
42
  if (!sourceContext) return;
42
43
 
43
44
  const value = args[0];
@@ -45,8 +46,9 @@ module.exports = function(core) {
45
46
 
46
47
  const sinkContext = captureStacktrace(
47
48
  { name, value },
48
- { constructorOpt: hooked }
49
+ { constructorOpt: hooked, prependFrames: [orig] }
49
50
  );
51
+
50
52
  inputTracing.handleSqlInjection(sourceContext, sinkContext);
51
53
  }
52
54
  });