@contrast/assess 1.17.0 → 1.19.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.
- package/lib/constants.js +26 -0
- package/lib/crypto-analysis/common.js +20 -0
- package/lib/crypto-analysis/index.js +44 -0
- package/lib/crypto-analysis/install/crypto.js +151 -0
- package/lib/crypto-analysis/install/math.js +99 -0
- package/lib/dataflow/propagation/index.js +2 -1
- package/lib/dataflow/propagation/install/JSON/parse.js +12 -11
- package/lib/dataflow/propagation/install/JSON/stringify.js +1 -1
- package/lib/dataflow/propagation/install/array-prototype-join.js +1 -1
- package/lib/dataflow/propagation/install/ejs/escape-xml.js +2 -2
- package/lib/dataflow/propagation/install/ejs/index.js +1 -0
- package/lib/dataflow/propagation/install/ejs/template.js +77 -0
- package/lib/dataflow/propagation/install/sequelize/index.js +31 -0
- package/lib/dataflow/propagation/install/sequelize/query-generator.js +90 -0
- package/lib/dataflow/propagation/install/{sequelize.js → sequelize/sql-string.js} +3 -3
- package/lib/dataflow/propagation/install/util-format.js +126 -0
- package/lib/dataflow/sinks/index.js +1 -0
- package/lib/dataflow/sinks/install/child-process.js +20 -14
- package/lib/dataflow/sinks/install/eval.js +16 -14
- package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +14 -8
- package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +12 -5
- package/lib/dataflow/sinks/install/fs.js +7 -7
- package/lib/dataflow/sinks/install/function.js +8 -12
- package/lib/dataflow/sinks/install/http/request.js +16 -8
- package/lib/dataflow/sinks/install/http/server-response.js +11 -2
- package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +15 -8
- package/lib/dataflow/sinks/install/libxmljs.js +15 -10
- package/lib/dataflow/sinks/install/marsdb.js +13 -8
- package/lib/dataflow/sinks/install/mongodb.js +25 -15
- package/lib/dataflow/sinks/install/mssql.js +20 -9
- package/lib/dataflow/sinks/install/mysql.js +15 -8
- package/lib/dataflow/sinks/install/node-serialize.js +101 -0
- package/lib/dataflow/sinks/install/postgres.js +17 -4
- package/lib/dataflow/sinks/install/sequelize.js +16 -9
- package/lib/dataflow/sinks/install/sqlite3.js +20 -7
- package/lib/dataflow/sinks/install/vm.js +19 -17
- package/lib/dataflow/sources/install/http.js +14 -42
- package/lib/dataflow/sources/install/koa/index.js +1 -0
- package/lib/dataflow/sources/install/koa/koa-multer.js +102 -0
- package/lib/dataflow/sources/install/multer1.js +25 -51
- package/lib/dataflow/sources/install/querystring.js +1 -4
- package/lib/event-factory.js +47 -0
- package/lib/get-policy.js +68 -0
- package/lib/get-source-context.js +62 -0
- package/lib/index.d.ts +50 -0
- package/lib/index.js +20 -19
- package/lib/make-source-context.js +74 -0
- package/lib/response-scanning/handlers/index.js +55 -28
- package/lib/response-scanning/install/http.js +13 -7
- package/lib/rule-scopes.js +48 -0
- package/lib/session-configuration/handlers.js +4 -3
- package/lib/session-configuration/install/express-session.js +8 -2
- package/package.json +2 -2
|
@@ -15,9 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const { patchType } = require('../common');
|
|
19
18
|
const {
|
|
20
|
-
Rule: { XXE },
|
|
19
|
+
Rule: { XXE: ruleId },
|
|
21
20
|
isString,
|
|
22
21
|
DataflowTag: {
|
|
23
22
|
UNTRUSTED,
|
|
@@ -26,18 +25,29 @@ const {
|
|
|
26
25
|
},
|
|
27
26
|
inspect
|
|
28
27
|
} = require('@contrast/common');
|
|
28
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
29
|
+
const { patchType } = require('../common');
|
|
29
30
|
|
|
30
31
|
const safeTags = [
|
|
31
32
|
LIMITED_CHARS,
|
|
32
33
|
ALPHANUM_SPACE_HYPHEN
|
|
33
34
|
];
|
|
34
35
|
|
|
36
|
+
/**
|
|
37
|
+
* @param {{
|
|
38
|
+
* assess: import('@contrast/assess').Assess,
|
|
39
|
+
* config: import('@contrast/config').Config,
|
|
40
|
+
* logger: import('@contrast/logger').Logger,
|
|
41
|
+
* messages: import('@contrast/common').Messages,
|
|
42
|
+
* }} core
|
|
43
|
+
* @returns {import('@contrast/common').Installable}
|
|
44
|
+
*/
|
|
35
45
|
module.exports = function(core) {
|
|
36
46
|
const {
|
|
37
47
|
depHooks,
|
|
38
48
|
patcher,
|
|
39
|
-
scopes: { sources, instrumentation },
|
|
40
49
|
assess: {
|
|
50
|
+
getSourceContext,
|
|
41
51
|
eventFactory: { createSinkEvent },
|
|
42
52
|
dataflow: {
|
|
43
53
|
tracker,
|
|
@@ -60,12 +70,7 @@ module.exports = function(core) {
|
|
|
60
70
|
name: `${moduleName}.${method}`,
|
|
61
71
|
patchType,
|
|
62
72
|
pre(data) {
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
!store ||
|
|
66
|
-
!data.args[0] ||
|
|
67
|
-
instrumentation.isLocked()
|
|
68
|
-
) return;
|
|
73
|
+
if (!getSourceContext(RULE, ruleId) || !data.args[0]) return;
|
|
69
74
|
|
|
70
75
|
const [xmlString, opts] = data.args;
|
|
71
76
|
|
|
@@ -104,7 +109,7 @@ module.exports = function(core) {
|
|
|
104
109
|
|
|
105
110
|
if (event) {
|
|
106
111
|
reportFindings({
|
|
107
|
-
ruleId
|
|
112
|
+
ruleId,
|
|
108
113
|
sinkEvent: event,
|
|
109
114
|
});
|
|
110
115
|
}
|
|
@@ -15,10 +15,9 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const util = require('util');
|
|
18
|
-
const { patchType } = require('../common');
|
|
19
18
|
const {
|
|
20
19
|
traverseValues,
|
|
21
|
-
Rule,
|
|
20
|
+
Rule: { NOSQL_INJECTION_MONGO: ruleId },
|
|
22
21
|
DataflowTag: {
|
|
23
22
|
ALPHANUM_SPACE_HYPHEN,
|
|
24
23
|
LIMITED_CHARS,
|
|
@@ -27,6 +26,8 @@ const {
|
|
|
27
26
|
CUSTOM_VALIDATED_NOSQL_INJECTION,
|
|
28
27
|
},
|
|
29
28
|
} = require('@contrast/common');
|
|
29
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
30
|
+
const { patchType } = require('../common');
|
|
30
31
|
|
|
31
32
|
const collectionMethods = ['find', 'findOne', 'update', 'remove'];
|
|
32
33
|
const querySafeTags = [
|
|
@@ -36,13 +37,20 @@ const querySafeTags = [
|
|
|
36
37
|
CUSTOM_VALIDATED_NOSQL_INJECTION,
|
|
37
38
|
];
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @param {{
|
|
42
|
+
* assess: import('@contrast/assess').Assess,
|
|
43
|
+
* logger: import('@contrast/logger').Logger,
|
|
44
|
+
* }} core
|
|
45
|
+
* @returns {import('@contrast/common').Installable}
|
|
46
|
+
*/
|
|
39
47
|
module.exports = function(core) {
|
|
40
48
|
const {
|
|
41
49
|
depHooks,
|
|
42
50
|
logger,
|
|
43
51
|
patcher,
|
|
44
|
-
scopes: { sources, instrumentation },
|
|
45
52
|
assess: {
|
|
53
|
+
getSourceContext,
|
|
46
54
|
eventFactory: { createSinkEvent },
|
|
47
55
|
dataflow: {
|
|
48
56
|
tracker,
|
|
@@ -82,10 +90,7 @@ module.exports = function(core) {
|
|
|
82
90
|
name,
|
|
83
91
|
patchType,
|
|
84
92
|
around(next, data) {
|
|
85
|
-
|
|
86
|
-
if (!sourceCtx || instrumentation.isLocked()) {
|
|
87
|
-
return next();
|
|
88
|
-
}
|
|
93
|
+
if (!getSourceContext(RULE, ruleId)) return next();
|
|
89
94
|
|
|
90
95
|
const argIdx = 0;
|
|
91
96
|
const result = getVulnerabilityInfo(data.args[argIdx]);
|
|
@@ -120,7 +125,7 @@ module.exports = function(core) {
|
|
|
120
125
|
});
|
|
121
126
|
|
|
122
127
|
if (sinkEvent) {
|
|
123
|
-
reportFindings({ ruleId
|
|
128
|
+
reportFindings({ ruleId, sinkEvent });
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
return next();
|
|
@@ -24,12 +24,13 @@ const {
|
|
|
24
24
|
LIMITED_CHARS,
|
|
25
25
|
STRING_TYPE_CHECKED,
|
|
26
26
|
},
|
|
27
|
-
Rule: { NOSQL_INJECTION_MONGO },
|
|
27
|
+
Rule: { NOSQL_INJECTION_MONGO: ruleId },
|
|
28
28
|
isNonEmptyObject,
|
|
29
29
|
traverseValues,
|
|
30
30
|
isString,
|
|
31
31
|
inspect
|
|
32
32
|
} = require('@contrast/common');
|
|
33
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
33
34
|
const utils = require('../../tag-utils');
|
|
34
35
|
const { patchType, filterSafeTags } = require('../common');
|
|
35
36
|
|
|
@@ -66,19 +67,28 @@ const querySafeTags = [
|
|
|
66
67
|
STRING_TYPE_CHECKED,
|
|
67
68
|
];
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @param {{
|
|
73
|
+
* assess: import('@contrast/assess').Assess,
|
|
74
|
+
* config: import('@contrast/config').Config,
|
|
75
|
+
* }} core
|
|
76
|
+
* @returns {import('@contrast/common').Installable}
|
|
77
|
+
*/
|
|
69
78
|
module.exports = function(core) {
|
|
70
79
|
const {
|
|
71
80
|
config,
|
|
72
81
|
depHooks,
|
|
73
82
|
logger,
|
|
74
83
|
patcher,
|
|
75
|
-
scopes: { sources, instrumentation },
|
|
76
84
|
assess: {
|
|
85
|
+
getSourceContext,
|
|
77
86
|
eventFactory: { createSinkEvent },
|
|
78
87
|
dataflow: {
|
|
79
88
|
tracker,
|
|
80
|
-
sinks: { isVulnerable,
|
|
81
|
-
}
|
|
89
|
+
sinks: { isVulnerable, reportFindings, reportSafePositive }
|
|
90
|
+
},
|
|
91
|
+
ruleScopes,
|
|
82
92
|
}
|
|
83
93
|
} = core;
|
|
84
94
|
|
|
@@ -228,17 +238,13 @@ module.exports = function(core) {
|
|
|
228
238
|
function createAroundHook(entity, name, method, getInfoMethod, vulnerableArgIdxs) {
|
|
229
239
|
const argsIdxsToCheck = vulnerableArgIdxs || [0];
|
|
230
240
|
return function(next, data) {
|
|
231
|
-
|
|
232
|
-
const sourceCtx = sources.getStore()?.assess;
|
|
233
|
-
|
|
234
|
-
if (isLocked(NOSQL_INJECTION_MONGO) || instrumentation.isLocked() || !sourceCtx) {
|
|
235
|
-
return next();
|
|
236
|
-
}
|
|
241
|
+
if (!getSourceContext(RULE, ruleId)) return next();
|
|
237
242
|
|
|
243
|
+
const { obj, args: origArgs } = data;
|
|
244
|
+
const safeReports = [];
|
|
238
245
|
let vulnInfo;
|
|
239
246
|
let reportSafe;
|
|
240
247
|
let vulnArgIdx;
|
|
241
|
-
const safeReports = [];
|
|
242
248
|
|
|
243
249
|
try {
|
|
244
250
|
for (const argIdx of argsIdxsToCheck) {
|
|
@@ -272,13 +278,15 @@ module.exports = function(core) {
|
|
|
272
278
|
|
|
273
279
|
reportSafePositive({
|
|
274
280
|
name,
|
|
275
|
-
ruleId
|
|
281
|
+
ruleId,
|
|
276
282
|
safeTags,
|
|
277
283
|
strInfo: strInfo.length === 1 ? strInfo[0] : strInfo
|
|
278
284
|
});
|
|
279
285
|
}
|
|
280
286
|
|
|
281
|
-
return methodsWithNestedCalls.includes(method)
|
|
287
|
+
return methodsWithNestedCalls.includes(method)
|
|
288
|
+
? ruleScopes.run(ruleId, async () => await next())
|
|
289
|
+
: next();
|
|
282
290
|
}
|
|
283
291
|
|
|
284
292
|
const { path, strInfo } = vulnInfo;
|
|
@@ -313,13 +321,15 @@ module.exports = function(core) {
|
|
|
313
321
|
});
|
|
314
322
|
|
|
315
323
|
if (sinkEvent) {
|
|
316
|
-
reportFindings({ ruleId
|
|
324
|
+
reportFindings({ ruleId, sinkEvent });
|
|
317
325
|
}
|
|
318
326
|
} catch (err) {
|
|
319
327
|
core.logger.error({ name, err }, 'assess sink analysis failed');
|
|
320
328
|
}
|
|
321
329
|
|
|
322
|
-
return methodsWithNestedCalls.includes(method)
|
|
330
|
+
return methodsWithNestedCalls.includes(method)
|
|
331
|
+
? ruleScopes.run(ruleId, async () => await next())
|
|
332
|
+
: next();
|
|
323
333
|
};
|
|
324
334
|
}
|
|
325
335
|
|
|
@@ -16,10 +16,17 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const {
|
|
19
|
-
DataflowTag: {
|
|
20
|
-
|
|
19
|
+
DataflowTag: {
|
|
20
|
+
CUSTOM_VALIDATED,
|
|
21
|
+
CUSTOM_ENCODED,
|
|
22
|
+
LIMITED_CHARS,
|
|
23
|
+
SQL_ENCODED,
|
|
24
|
+
UNTRUSTED,
|
|
25
|
+
},
|
|
26
|
+
Rule: { SQL_INJECTION: ruleId },
|
|
21
27
|
isString
|
|
22
28
|
} = require('@contrast/common');
|
|
29
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
23
30
|
const { createModuleLabel } = require('../../propagation/common');
|
|
24
31
|
const { patchType, filterSafeTags } = require('../common');
|
|
25
32
|
|
|
@@ -30,15 +37,20 @@ const safeTags = [
|
|
|
30
37
|
CUSTOM_ENCODED,
|
|
31
38
|
];
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
/**
|
|
41
|
+
* @param {{
|
|
42
|
+
* assess: import('@contrast/assess').Assess,
|
|
43
|
+
* config: import('@contrast/config').Config,
|
|
44
|
+
* }} core
|
|
45
|
+
* @returns {import('@contrast/common').Installable}
|
|
46
|
+
*/
|
|
35
47
|
module.exports = function(core) {
|
|
36
48
|
const {
|
|
37
49
|
depHooks,
|
|
38
50
|
patcher,
|
|
39
51
|
config,
|
|
40
|
-
scopes: { sources },
|
|
41
52
|
assess: {
|
|
53
|
+
getSourceContext,
|
|
42
54
|
eventFactory: { createSinkEvent },
|
|
43
55
|
dataflow: {
|
|
44
56
|
tracker,
|
|
@@ -48,12 +60,11 @@ module.exports = function(core) {
|
|
|
48
60
|
} = core;
|
|
49
61
|
|
|
50
62
|
const pre = (name, method, obj, version) => (data) => {
|
|
51
|
-
const store = sources.getStore()?.assess;
|
|
52
63
|
if (
|
|
53
|
-
!
|
|
64
|
+
!getSourceContext(RULE, ruleId) ||
|
|
54
65
|
!data.args[0] ||
|
|
55
66
|
!isString(data.args[0]) ||
|
|
56
|
-
isLocked(
|
|
67
|
+
isLocked(ruleId)
|
|
57
68
|
) return;
|
|
58
69
|
|
|
59
70
|
const strInfo = tracker.getData(data.args[0]);
|
|
@@ -86,7 +97,7 @@ module.exports = function(core) {
|
|
|
86
97
|
|
|
87
98
|
if (event) {
|
|
88
99
|
reportFindings({
|
|
89
|
-
ruleId
|
|
100
|
+
ruleId,
|
|
90
101
|
sinkEvent: event,
|
|
91
102
|
});
|
|
92
103
|
}
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const { patchType } = require('../common');
|
|
19
19
|
const {
|
|
20
|
-
Rule: { SQL_INJECTION },
|
|
21
|
-
isString,
|
|
20
|
+
Rule: { SQL_INJECTION: ruleId },
|
|
22
21
|
DataflowTag: {
|
|
23
22
|
CUSTOM_ENCODED_SQL_INJECTION,
|
|
24
23
|
CUSTOM_ENCODED,
|
|
@@ -28,8 +27,10 @@ const {
|
|
|
28
27
|
LIMITED_CHARS,
|
|
29
28
|
UNTRUSTED
|
|
30
29
|
},
|
|
31
|
-
|
|
30
|
+
isString,
|
|
31
|
+
inspect,
|
|
32
32
|
} = require('@contrast/common');
|
|
33
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
33
34
|
|
|
34
35
|
const safeTags = [
|
|
35
36
|
CUSTOM_ENCODED_SQL_INJECTION,
|
|
@@ -40,12 +41,19 @@ const safeTags = [
|
|
|
40
41
|
LIMITED_CHARS,
|
|
41
42
|
];
|
|
42
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @param {{
|
|
46
|
+
* assess: import('@contrast/assess').Assess,
|
|
47
|
+
* config: import('@contrast/config').Config,
|
|
48
|
+
* }} core
|
|
49
|
+
* @returns {import('@contrast/common').Installable}
|
|
50
|
+
*/
|
|
43
51
|
module.exports = function(core) {
|
|
44
52
|
const {
|
|
45
53
|
depHooks,
|
|
46
54
|
patcher,
|
|
47
|
-
scopes: { sources },
|
|
48
55
|
assess: {
|
|
56
|
+
getSourceContext,
|
|
49
57
|
eventFactory: { createSinkEvent },
|
|
50
58
|
dataflow: {
|
|
51
59
|
tracker,
|
|
@@ -65,11 +73,10 @@ module.exports = function(core) {
|
|
|
65
73
|
}
|
|
66
74
|
|
|
67
75
|
const pre = (module, file, obj, method) => (data) => {
|
|
68
|
-
const store = sources.getStore()?.assess;
|
|
69
76
|
if (
|
|
70
|
-
!
|
|
77
|
+
!getSourceContext(RULE, ruleId) ||
|
|
71
78
|
!data.args[0] ||
|
|
72
|
-
isLocked(
|
|
79
|
+
isLocked(ruleId)
|
|
73
80
|
) return;
|
|
74
81
|
|
|
75
82
|
const val = getValueFromArgs(data.args);
|
|
@@ -106,7 +113,7 @@ module.exports = function(core) {
|
|
|
106
113
|
|
|
107
114
|
if (event) {
|
|
108
115
|
reportFindings({
|
|
109
|
-
ruleId
|
|
116
|
+
ruleId,
|
|
110
117
|
sinkEvent: event,
|
|
111
118
|
});
|
|
112
119
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright: 2023 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 {
|
|
19
|
+
Rule: { UNTRUSTED_DESERIALIZATION: ruleId },
|
|
20
|
+
isString,
|
|
21
|
+
DataflowTag: {
|
|
22
|
+
UNTRUSTED
|
|
23
|
+
}
|
|
24
|
+
} = require('@contrast/common');
|
|
25
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
26
|
+
const { patchType } = require('../common');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {{
|
|
30
|
+
* assess: import('@contrast/assess').Assess,
|
|
31
|
+
* config: import('@contrast/config').Config,
|
|
32
|
+
* }} core
|
|
33
|
+
* @returns {import('@contrast/common').Installable}
|
|
34
|
+
*/
|
|
35
|
+
module.exports = function(core) {
|
|
36
|
+
const {
|
|
37
|
+
depHooks,
|
|
38
|
+
patcher,
|
|
39
|
+
assess: {
|
|
40
|
+
getSourceContext,
|
|
41
|
+
eventFactory: { createSinkEvent },
|
|
42
|
+
dataflow: {
|
|
43
|
+
tracker,
|
|
44
|
+
sinks: { isVulnerable, reportFindings }
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
} = core;
|
|
48
|
+
|
|
49
|
+
core.assess.dataflow.sinks.nodeSerialize = {
|
|
50
|
+
install() {
|
|
51
|
+
depHooks.resolve({ name: 'node-serialize' }, (nodeSerialize) => {
|
|
52
|
+
patcher.patch(nodeSerialize, 'unserialize', {
|
|
53
|
+
name: 'node-serialize.unserialize',
|
|
54
|
+
patchType,
|
|
55
|
+
pre(data) {
|
|
56
|
+
if (!getSourceContext(RULE, ruleId) || !data.args[0]) return;
|
|
57
|
+
|
|
58
|
+
const [input] = data.args;
|
|
59
|
+
if (!isString(input)) return;
|
|
60
|
+
|
|
61
|
+
const strInfo = tracker.getData(input);
|
|
62
|
+
if (!strInfo || !isVulnerable(UNTRUSTED, [], strInfo.tags)) return;
|
|
63
|
+
|
|
64
|
+
const sinkEvent = createSinkEvent({
|
|
65
|
+
name: 'node-serialize.unserialize',
|
|
66
|
+
moduleName: 'node-serialize',
|
|
67
|
+
methodName: 'unserialize',
|
|
68
|
+
context: `node-serialize.unserialize(${strInfo.value})`,
|
|
69
|
+
history: [strInfo],
|
|
70
|
+
object: {
|
|
71
|
+
value: 'node-serialize',
|
|
72
|
+
tracked: false
|
|
73
|
+
},
|
|
74
|
+
args: [
|
|
75
|
+
{
|
|
76
|
+
value: strInfo.value,
|
|
77
|
+
tracked: true
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
tags: strInfo.tags,
|
|
81
|
+
source: 'P0',
|
|
82
|
+
stacktraceOpts: {
|
|
83
|
+
contructorOpt: data.hooked,
|
|
84
|
+
prependFrames: [data.orig]
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (sinkEvent) {
|
|
89
|
+
reportFindings({
|
|
90
|
+
ruleId,
|
|
91
|
+
sinkEvent,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
return core.assess.dataflow.sinks.nodeSerialize;
|
|
101
|
+
};
|
|
@@ -17,19 +17,33 @@
|
|
|
17
17
|
|
|
18
18
|
const util = require('util');
|
|
19
19
|
const {
|
|
20
|
-
DataflowTag: {
|
|
20
|
+
DataflowTag: {
|
|
21
|
+
CUSTOM_VALIDATED,
|
|
22
|
+
CUSTOM_ENCODED,
|
|
23
|
+
LIMITED_CHARS,
|
|
24
|
+
SQL_ENCODED,
|
|
25
|
+
UNTRUSTED,
|
|
26
|
+
},
|
|
21
27
|
Rule: { SQL_INJECTION: ruleId },
|
|
22
28
|
isString,
|
|
23
29
|
} = require('@contrast/common');
|
|
30
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
24
31
|
const { filterSafeTags, patchType } = require('../common');
|
|
25
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @param {{
|
|
35
|
+
* assess: import('@contrast/assess').Assess,
|
|
36
|
+
* config: import('@contrast/config').Config,
|
|
37
|
+
* }} core
|
|
38
|
+
* @returns {import('@contrast/common').Installable}
|
|
39
|
+
*/
|
|
26
40
|
module.exports = function(core) {
|
|
27
41
|
const {
|
|
28
42
|
config,
|
|
29
43
|
depHooks,
|
|
30
44
|
patcher,
|
|
31
|
-
scopes: { sources },
|
|
32
45
|
assess: {
|
|
46
|
+
getSourceContext,
|
|
33
47
|
eventFactory: { createSinkEvent },
|
|
34
48
|
dataflow: {
|
|
35
49
|
tracker,
|
|
@@ -50,8 +64,7 @@ module.exports = function(core) {
|
|
|
50
64
|
const postgres = core.assess.dataflow.sinks.postgres = {};
|
|
51
65
|
|
|
52
66
|
const preHook = (methodSignature) => (data) => {
|
|
53
|
-
|
|
54
|
-
if (!assessStore || isLocked(ruleId)) return;
|
|
67
|
+
if (!getSourceContext(RULE, ruleId) || isLocked(ruleId)) return;
|
|
55
68
|
|
|
56
69
|
const [arg0] = data.args;
|
|
57
70
|
const query = arg0?.text || arg0;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
const util = require('util');
|
|
19
19
|
const {
|
|
20
|
-
Rule: { SQL_INJECTION },
|
|
20
|
+
Rule: { SQL_INJECTION: ruleId },
|
|
21
21
|
DataflowTag: {
|
|
22
22
|
UNTRUSTED,
|
|
23
23
|
SQL_ENCODED,
|
|
@@ -26,15 +26,23 @@ const {
|
|
|
26
26
|
CUSTOM_ENCODED,
|
|
27
27
|
},
|
|
28
28
|
} = require('@contrast/common');
|
|
29
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
29
30
|
const { patchType, filterSafeTags } = require('../common');
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {{
|
|
34
|
+
* assess: import('@contrast/assess').Assess,
|
|
35
|
+
* config: import('@contrast/config').Config,
|
|
36
|
+
* }} core
|
|
37
|
+
* @returns {import('@contrast/common').Installable}
|
|
38
|
+
*/
|
|
31
39
|
module.exports = function(core) {
|
|
32
40
|
const {
|
|
33
41
|
depHooks,
|
|
34
42
|
patcher,
|
|
35
43
|
config,
|
|
36
|
-
scopes: { sources },
|
|
37
44
|
assess: {
|
|
45
|
+
getSourceContext,
|
|
38
46
|
eventFactory: { createSinkEvent },
|
|
39
47
|
dataflow: {
|
|
40
48
|
tracker,
|
|
@@ -61,10 +69,9 @@ module.exports = function(core) {
|
|
|
61
69
|
name: sequelizeQueryPatchName,
|
|
62
70
|
patchType,
|
|
63
71
|
around(next, data) {
|
|
64
|
-
|
|
65
|
-
const sourceContext = sources.getStore()?.assess;
|
|
66
|
-
if (!sourceContext || !args[0]) return next();
|
|
72
|
+
if (!getSourceContext(RULE, ruleId) || !data.args[0]) return next();
|
|
67
73
|
|
|
74
|
+
const { args, hooked, orig } = data;
|
|
68
75
|
const query = typeof args[0] === 'string' ? args[0] : args[0].query;
|
|
69
76
|
|
|
70
77
|
try {
|
|
@@ -74,7 +81,7 @@ module.exports = function(core) {
|
|
|
74
81
|
if (queryInfo && !isVulnerableQuery && config.assess.safe_positives.enable) {
|
|
75
82
|
reportSafePositive({
|
|
76
83
|
name: sequelizeQueryPatchName,
|
|
77
|
-
ruleId
|
|
84
|
+
ruleId,
|
|
78
85
|
safeTags: filterSafeTags(safeTags, queryInfo),
|
|
79
86
|
strInfo: {
|
|
80
87
|
value: queryInfo?.value,
|
|
@@ -87,7 +94,7 @@ module.exports = function(core) {
|
|
|
87
94
|
!queryInfo ||
|
|
88
95
|
!isVulnerableQuery
|
|
89
96
|
) {
|
|
90
|
-
return runInActiveSink(
|
|
97
|
+
return runInActiveSink(ruleId, async () => await next());
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
const sqlValue =
|
|
@@ -122,7 +129,7 @@ module.exports = function(core) {
|
|
|
122
129
|
|
|
123
130
|
if (event) {
|
|
124
131
|
reportFindings({
|
|
125
|
-
ruleId
|
|
132
|
+
ruleId,
|
|
126
133
|
sinkEvent: event,
|
|
127
134
|
});
|
|
128
135
|
}
|
|
@@ -134,7 +141,7 @@ module.exports = function(core) {
|
|
|
134
141
|
);
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
return runInActiveSink(
|
|
144
|
+
return runInActiveSink(ruleId, async () => await next());
|
|
138
145
|
},
|
|
139
146
|
});
|
|
140
147
|
});
|
|
@@ -17,10 +17,17 @@
|
|
|
17
17
|
|
|
18
18
|
const { patchType } = require('../common');
|
|
19
19
|
const {
|
|
20
|
-
DataflowTag: {
|
|
21
|
-
|
|
20
|
+
DataflowTag: {
|
|
21
|
+
CUSTOM_VALIDATED,
|
|
22
|
+
CUSTOM_ENCODED,
|
|
23
|
+
LIMITED_CHARS,
|
|
24
|
+
SQL_ENCODED,
|
|
25
|
+
UNTRUSTED,
|
|
26
|
+
},
|
|
27
|
+
Rule: { SQL_INJECTION: ruleId },
|
|
22
28
|
isString
|
|
23
29
|
} = require('@contrast/common');
|
|
30
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
24
31
|
|
|
25
32
|
const safeTags = [
|
|
26
33
|
SQL_ENCODED,
|
|
@@ -29,12 +36,19 @@ const safeTags = [
|
|
|
29
36
|
CUSTOM_ENCODED,
|
|
30
37
|
];
|
|
31
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @param {{
|
|
41
|
+
* assess: import('@contrast/assess').Assess,
|
|
42
|
+
* config: import('@contrast/config').Config,
|
|
43
|
+
* }} core
|
|
44
|
+
* @returns {import('@contrast/common').Installable}
|
|
45
|
+
*/
|
|
32
46
|
module.exports = function(core) {
|
|
33
47
|
const {
|
|
34
48
|
depHooks,
|
|
35
49
|
patcher,
|
|
36
|
-
scopes: { sources },
|
|
37
50
|
assess: {
|
|
51
|
+
getSourceContext,
|
|
38
52
|
eventFactory: { createSinkEvent },
|
|
39
53
|
dataflow: {
|
|
40
54
|
tracker,
|
|
@@ -44,12 +58,11 @@ module.exports = function(core) {
|
|
|
44
58
|
} = core;
|
|
45
59
|
|
|
46
60
|
const pre = (name, method) => (data) => {
|
|
47
|
-
const store = sources.getStore()?.assess;
|
|
48
61
|
if (
|
|
49
|
-
!
|
|
62
|
+
!getSourceContext(RULE, ruleId) ||
|
|
50
63
|
!data.args[0] ||
|
|
51
64
|
!isString(data.args[0]) ||
|
|
52
|
-
isLocked(
|
|
65
|
+
isLocked(ruleId)
|
|
53
66
|
) return;
|
|
54
67
|
|
|
55
68
|
const strInfo = tracker.getData(data.args[0]);
|
|
@@ -83,7 +96,7 @@ module.exports = function(core) {
|
|
|
83
96
|
|
|
84
97
|
if (event) {
|
|
85
98
|
reportFindings({
|
|
86
|
-
ruleId
|
|
99
|
+
ruleId,
|
|
87
100
|
sinkEvent: event,
|
|
88
101
|
});
|
|
89
102
|
}
|