@contrast/assess 1.18.0 → 1.20.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/LICENSE +1 -1
- 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 +156 -0
- package/lib/crypto-analysis/install/math.js +104 -0
- package/lib/dataflow/index.js +1 -1
- package/lib/dataflow/propagation/common.js +1 -1
- package/lib/dataflow/propagation/index.js +1 -1
- package/lib/dataflow/propagation/install/JSON/index.js +1 -1
- package/lib/dataflow/propagation/install/JSON/parse-fn.js +1 -1
- package/lib/dataflow/propagation/install/JSON/parse.js +15 -14
- package/lib/dataflow/propagation/install/JSON/stringify.js +2 -2
- package/lib/dataflow/propagation/install/array-prototype-join.js +1 -1
- package/lib/dataflow/propagation/install/buffer.js +1 -1
- package/lib/dataflow/propagation/install/contrast-methods/add.js +1 -1
- package/lib/dataflow/propagation/install/contrast-methods/index.js +1 -1
- package/lib/dataflow/propagation/install/contrast-methods/number.js +4 -3
- package/lib/dataflow/propagation/install/contrast-methods/string.js +1 -1
- package/lib/dataflow/propagation/install/contrast-methods/tag.js +1 -1
- package/lib/dataflow/propagation/install/decode-uri-component.js +1 -1
- package/lib/dataflow/propagation/install/ejs/escape-xml.js +3 -3
- package/lib/dataflow/propagation/install/ejs/index.js +2 -1
- package/lib/dataflow/propagation/install/ejs/template.js +79 -0
- package/lib/dataflow/propagation/install/encode-uri.js +1 -1
- package/lib/dataflow/propagation/install/escape-html.js +1 -1
- package/lib/dataflow/propagation/install/escape.js +1 -1
- package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +1 -1
- package/lib/dataflow/propagation/install/isnumeric-0.js +3 -3
- package/lib/dataflow/propagation/install/joi/any.js +1 -1
- package/lib/dataflow/propagation/install/joi/boolean.js +1 -1
- package/lib/dataflow/propagation/install/joi/expression.js +1 -1
- package/lib/dataflow/propagation/install/joi/index.js +1 -1
- package/lib/dataflow/propagation/install/joi/keys.js +1 -1
- package/lib/dataflow/propagation/install/joi/number.js +1 -1
- package/lib/dataflow/propagation/install/joi/object.js +1 -1
- package/lib/dataflow/propagation/install/joi/string-schema.js +1 -1
- package/lib/dataflow/propagation/install/joi/utils.js +1 -1
- package/lib/dataflow/propagation/install/joi/values.js +1 -1
- package/lib/dataflow/propagation/install/mongoose/common.js +1 -1
- package/lib/dataflow/propagation/install/mongoose/index.js +1 -1
- package/lib/dataflow/propagation/install/mongoose/schema-map.js +1 -1
- package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +1 -1
- package/lib/dataflow/propagation/install/mongoose/schema-string.js +1 -1
- package/lib/dataflow/propagation/install/mustache-escape.js +1 -1
- package/lib/dataflow/propagation/install/mysql-connection-escape.js +1 -1
- package/lib/dataflow/propagation/install/parse-int.js +3 -3
- package/lib/dataflow/propagation/install/path/basename.js +1 -1
- package/lib/dataflow/propagation/install/path/common.js +1 -1
- package/lib/dataflow/propagation/install/path/dirname.js +1 -1
- package/lib/dataflow/propagation/install/path/extname.js +1 -1
- package/lib/dataflow/propagation/install/path/format.js +1 -1
- package/lib/dataflow/propagation/install/path/index.js +1 -1
- package/lib/dataflow/propagation/install/path/join-and-resolve.js +1 -1
- package/lib/dataflow/propagation/install/path/normalize.js +1 -1
- package/lib/dataflow/propagation/install/path/parse.js +1 -1
- package/lib/dataflow/propagation/install/path/relative.js +1 -1
- package/lib/dataflow/propagation/install/path/toNamespacedPath.js +1 -1
- package/lib/dataflow/propagation/install/pug/index.js +3 -3
- package/lib/dataflow/propagation/install/pug-runtime-escape.js +1 -1
- package/lib/dataflow/propagation/install/querystring/escape.js +1 -1
- package/lib/dataflow/propagation/install/querystring/index.js +1 -1
- package/lib/dataflow/propagation/install/querystring/parse.js +1 -1
- package/lib/dataflow/propagation/install/querystring/stringify.js +1 -1
- package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +1 -1
- package/lib/dataflow/propagation/install/send.js +1 -1
- package/lib/dataflow/propagation/install/sequelize/index.js +1 -1
- package/lib/dataflow/propagation/install/sequelize/query-generator.js +1 -1
- package/lib/dataflow/propagation/install/sequelize/sql-string.js +1 -1
- package/lib/dataflow/propagation/install/sql-template-strings.js +1 -1
- package/lib/dataflow/propagation/install/string/concat.js +1 -1
- package/lib/dataflow/propagation/install/string/format-methods.js +1 -1
- package/lib/dataflow/propagation/install/string/html-methods.js +1 -1
- package/lib/dataflow/propagation/install/string/index.js +1 -1
- package/lib/dataflow/propagation/install/string/match-all.js +1 -1
- package/lib/dataflow/propagation/install/string/match.js +1 -1
- package/lib/dataflow/propagation/install/string/replace.js +1 -1
- package/lib/dataflow/propagation/install/string/slice.js +1 -1
- package/lib/dataflow/propagation/install/string/split.js +1 -1
- package/lib/dataflow/propagation/install/string/substring.js +1 -1
- package/lib/dataflow/propagation/install/string/trim.js +1 -1
- package/lib/dataflow/propagation/install/unescape.js +1 -1
- package/lib/dataflow/propagation/install/url/domain-parsers.js +1 -1
- package/lib/dataflow/propagation/install/url/index.js +1 -1
- package/lib/dataflow/propagation/install/url/parse.js +1 -1
- package/lib/dataflow/propagation/install/url/searchParams.js +1 -1
- package/lib/dataflow/propagation/install/url/url.js +1 -1
- package/lib/dataflow/propagation/install/util-format.js +10 -4
- package/lib/dataflow/propagation/install/validator/hooks.js +1 -1
- package/lib/dataflow/propagation/install/validator/index.js +1 -1
- package/lib/dataflow/propagation/install/validator/methods.js +1 -1
- package/lib/dataflow/sinks/common.js +1 -1
- package/lib/dataflow/sinks/index.js +1 -1
- package/lib/dataflow/sinks/install/child-process.js +21 -15
- package/lib/dataflow/sinks/install/eval.js +17 -15
- package/lib/dataflow/sinks/install/express/index.js +1 -1
- package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +15 -9
- package/lib/dataflow/sinks/install/fastify/index.js +1 -1
- package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +13 -6
- package/lib/dataflow/sinks/install/fs.js +8 -8
- package/lib/dataflow/sinks/install/function.js +9 -13
- package/lib/dataflow/sinks/install/http/index.js +1 -1
- package/lib/dataflow/sinks/install/http/request.js +17 -9
- package/lib/dataflow/sinks/install/http/server-response.js +12 -3
- package/lib/dataflow/sinks/install/koa/index.js +1 -1
- package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +16 -9
- package/lib/dataflow/sinks/install/libxmljs.js +16 -11
- package/lib/dataflow/sinks/install/marsdb.js +17 -12
- package/lib/dataflow/sinks/install/mongodb.js +32 -22
- package/lib/dataflow/sinks/install/mssql.js +21 -10
- package/lib/dataflow/sinks/install/mysql.js +16 -9
- package/lib/dataflow/sinks/install/node-serialize.js +16 -18
- package/lib/dataflow/sinks/install/postgres.js +18 -5
- package/lib/dataflow/sinks/install/sequelize.js +23 -17
- package/lib/dataflow/sinks/install/sqlite3.js +21 -8
- package/lib/dataflow/sinks/install/vm.js +20 -18
- package/lib/dataflow/sources/common.js +1 -1
- package/lib/dataflow/sources/handler.js +11 -10
- package/lib/dataflow/sources/index.js +2 -2
- package/lib/dataflow/sources/install/body-parser1.js +11 -13
- package/lib/dataflow/sources/install/{busboy1.js → busboy.js} +15 -15
- package/lib/dataflow/sources/install/cookie-parser1.js +7 -6
- package/lib/dataflow/sources/install/express/index.js +1 -1
- package/lib/dataflow/sources/install/express/params.js +9 -10
- package/lib/dataflow/sources/install/express/parsedUrl.js +1 -1
- package/lib/dataflow/sources/install/fastify/fastify.js +6 -7
- package/lib/dataflow/sources/install/fastify/index.js +1 -1
- package/lib/dataflow/sources/install/formidable1.js +8 -6
- package/lib/dataflow/sources/install/http.js +17 -45
- package/lib/dataflow/sources/install/koa/index.js +2 -1
- package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +10 -9
- package/lib/dataflow/sources/install/koa/koa-multer.js +102 -0
- package/lib/dataflow/sources/install/koa/koa-routers.js +6 -8
- package/lib/dataflow/sources/install/koa/koa2.js +42 -38
- package/lib/dataflow/sources/install/multer1.js +26 -52
- package/lib/dataflow/sources/install/qs6.js +7 -6
- package/lib/dataflow/sources/install/querystring.js +5 -8
- package/lib/dataflow/tag-utils.js +1 -1
- package/lib/dataflow/tracker.js +1 -1
- package/lib/dataflow/utils/is-safe-content-type.js +1 -1
- package/lib/dataflow/utils/is-vulnerable.js +1 -1
- package/lib/event-factory.js +75 -26
- package/lib/get-policy.js +68 -0
- package/lib/get-source-context.js +62 -0
- package/lib/index.d.ts +64 -0
- package/lib/index.js +21 -20
- package/lib/make-source-context.js +78 -0
- package/lib/response-scanning/handlers/index.js +56 -29
- package/lib/response-scanning/handlers/utils.js +1 -1
- package/lib/response-scanning/index.js +1 -1
- package/lib/response-scanning/install/http.js +14 -8
- package/lib/rule-scopes.js +48 -0
- package/lib/session-configuration/common.js +1 -1
- package/lib/session-configuration/handlers.js +66 -47
- package/lib/session-configuration/index.js +3 -1
- package/lib/session-configuration/install/express-session.js +23 -26
- package/lib/session-configuration/install/fastify-cookie.js +110 -0
- package/lib/session-configuration/install/hapi.js +8 -11
- package/lib/session-configuration/install/koa.js +101 -0
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -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
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
const { patchType, filterSafeTags } = require('../common');
|
|
18
18
|
const {
|
|
19
|
-
isString,
|
|
20
19
|
DataflowTag: {
|
|
21
20
|
UNTRUSTED,
|
|
22
21
|
CUSTOM_ENCODED_TRUST_BOUNDARY_VIOLATION,
|
|
@@ -25,14 +24,17 @@ const {
|
|
|
25
24
|
CUSTOM_VALIDATED,
|
|
26
25
|
LIMITED_CHARS,
|
|
27
26
|
},
|
|
28
|
-
Rule: { UNSAFE_CODE_EXECUTION },
|
|
29
|
-
isNonEmptyObject,
|
|
27
|
+
Rule: { UNSAFE_CODE_EXECUTION: ruleId },
|
|
30
28
|
inspect,
|
|
31
|
-
|
|
29
|
+
isNonEmptyObject,
|
|
30
|
+
isString,
|
|
32
31
|
join,
|
|
33
32
|
split,
|
|
33
|
+
traverseValues,
|
|
34
34
|
} = require('@contrast/common');
|
|
35
|
+
const { InstrumentationType: { RULE } } = require('../../../constants');
|
|
35
36
|
const { createAdjustedQueryTags } = require('../../tag-utils');
|
|
37
|
+
|
|
36
38
|
const safeTags = [
|
|
37
39
|
CUSTOM_ENCODED_TRUST_BOUNDARY_VIOLATION,
|
|
38
40
|
CUSTOM_ENCODED,
|
|
@@ -41,13 +43,20 @@ const safeTags = [
|
|
|
41
43
|
LIMITED_CHARS,
|
|
42
44
|
];
|
|
43
45
|
|
|
46
|
+
/**
|
|
47
|
+
* @param {{
|
|
48
|
+
* assess: import('@contrast/assess').Assess,
|
|
49
|
+
* config: import('@contrast/config').Config,
|
|
50
|
+
* }} core
|
|
51
|
+
* @returns {import('@contrast/common').Installable}
|
|
52
|
+
*/
|
|
44
53
|
module.exports = function (core) {
|
|
45
54
|
const {
|
|
46
55
|
config,
|
|
47
56
|
depHooks,
|
|
48
57
|
patcher,
|
|
49
|
-
scopes: { sources, instrumentation },
|
|
50
58
|
assess: {
|
|
59
|
+
getSourceContext,
|
|
51
60
|
eventFactory: { createSinkEvent },
|
|
52
61
|
dataflow: {
|
|
53
62
|
tracker,
|
|
@@ -133,14 +142,7 @@ module.exports = function (core) {
|
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
function around(next, { args: origArgs, hooked, orig, name }) {
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
!store ||
|
|
139
|
-
instrumentation.isLocked() ||
|
|
140
|
-
isLocked(UNSAFE_CODE_EXECUTION)
|
|
141
|
-
) {
|
|
142
|
-
return next();
|
|
143
|
-
}
|
|
145
|
+
if (!getSourceContext(RULE, ruleId) || isLocked(ruleId)) return next();
|
|
144
146
|
|
|
145
147
|
const methodPath = split(name, '.');
|
|
146
148
|
const method = methodPath[methodPath.length - 1];
|
|
@@ -189,13 +191,13 @@ module.exports = function (core) {
|
|
|
189
191
|
|
|
190
192
|
reportSafePositive({
|
|
191
193
|
name,
|
|
192
|
-
ruleId
|
|
194
|
+
ruleId,
|
|
193
195
|
safeTags: Array.from(foundSafeTags),
|
|
194
196
|
strInfo,
|
|
195
197
|
});
|
|
196
198
|
|
|
197
199
|
return name === 'vm.runInNewContext'
|
|
198
|
-
? runInActiveSink(
|
|
200
|
+
? runInActiveSink(ruleId, () => next())
|
|
199
201
|
: next();
|
|
200
202
|
}
|
|
201
203
|
|
|
@@ -233,14 +235,14 @@ module.exports = function (core) {
|
|
|
233
235
|
|
|
234
236
|
if (event) {
|
|
235
237
|
reportFindings({
|
|
236
|
-
ruleId
|
|
238
|
+
ruleId,
|
|
237
239
|
sinkEvent: event,
|
|
238
240
|
});
|
|
239
241
|
}
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
return name === 'vm.runInNewContext'
|
|
243
|
-
? runInActiveSink(
|
|
245
|
+
? runInActiveSink(ruleId, () => next())
|
|
244
246
|
: next();
|
|
245
247
|
}
|
|
246
248
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -22,7 +22,7 @@ const {
|
|
|
22
22
|
join,
|
|
23
23
|
} = require('@contrast/common');
|
|
24
24
|
|
|
25
|
-
module.exports = function(core) {
|
|
25
|
+
module.exports = function (core) {
|
|
26
26
|
const {
|
|
27
27
|
assess: {
|
|
28
28
|
eventFactory,
|
|
@@ -33,9 +33,10 @@ module.exports = function(core) {
|
|
|
33
33
|
},
|
|
34
34
|
config,
|
|
35
35
|
createSnapshot,
|
|
36
|
-
logger,
|
|
37
36
|
} = core;
|
|
38
37
|
|
|
38
|
+
const logger = core.logger.child({ name: 'contrast:sources' });
|
|
39
|
+
|
|
39
40
|
const emptyStack = Object.freeze([]);
|
|
40
41
|
|
|
41
42
|
sources.createTags = function createTags({ inputType, fieldName = '', value }) {
|
|
@@ -55,13 +56,13 @@ module.exports = function(core) {
|
|
|
55
56
|
return tags;
|
|
56
57
|
};
|
|
57
58
|
|
|
58
|
-
sources.createStacktrace = function(stacktraceOpts) {
|
|
59
|
+
sources.createStacktrace = function (stacktraceOpts) {
|
|
59
60
|
return config.assess.stacktraces === 'NONE'
|
|
60
61
|
? emptyStack
|
|
61
62
|
: createSnapshot(stacktraceOpts)();
|
|
62
63
|
};
|
|
63
64
|
|
|
64
|
-
sources.handle = function({
|
|
65
|
+
sources.handle = function ({
|
|
65
66
|
context,
|
|
66
67
|
keys,
|
|
67
68
|
name,
|
|
@@ -73,7 +74,7 @@ module.exports = function(core) {
|
|
|
73
74
|
if (!data) return;
|
|
74
75
|
|
|
75
76
|
if (!sourceContext) {
|
|
76
|
-
|
|
77
|
+
logger.trace({ inputType, sourceName: name }, 'skipping assess source handling - no request context');
|
|
77
78
|
return null;
|
|
78
79
|
}
|
|
79
80
|
|
|
@@ -119,7 +120,7 @@ module.exports = function(core) {
|
|
|
119
120
|
const pathName = join(path, '.');
|
|
120
121
|
|
|
121
122
|
if (sourceContext.sourceEventsCount >= max) {
|
|
122
|
-
|
|
123
|
+
logger.trace({ inputType, sourceName: name }, 'exiting assess source handling - %s max events exceeded', max);
|
|
123
124
|
return true;
|
|
124
125
|
}
|
|
125
126
|
|
|
@@ -136,13 +137,13 @@ module.exports = function(core) {
|
|
|
136
137
|
|
|
137
138
|
const event = createEvent({ pathName, value, fieldName });
|
|
138
139
|
if (!event) {
|
|
139
|
-
|
|
140
|
+
logger.warn({ inputType, sourceName: name, pathName, value }, 'unable to create source event');
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
const { extern } = tracker.track(value, event);
|
|
144
145
|
if (extern) {
|
|
145
|
-
logger.trace({ extern, fieldName, name, inputType }, 'tracked');
|
|
146
|
+
logger.trace({ extern, fieldName, sourceName: name, inputType }, 'tracked');
|
|
146
147
|
obj[fieldName] = extern;
|
|
147
148
|
|
|
148
149
|
sourceContext.sourceEventsCount++;
|
|
@@ -152,7 +153,7 @@ module.exports = function(core) {
|
|
|
152
153
|
if (event) {
|
|
153
154
|
tracker.track(value, event);
|
|
154
155
|
} else {
|
|
155
|
-
|
|
156
|
+
logger.warn({ inputType, sourceName: name, pathName, value }, 'unable to create source event');
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -26,7 +26,7 @@ module.exports = function (core) {
|
|
|
26
26
|
require('./install/fastify')(core);
|
|
27
27
|
require('./install/koa')(core);
|
|
28
28
|
require('./install/body-parser1')(core);
|
|
29
|
-
require('./install/
|
|
29
|
+
require('./install/busboy')(core);
|
|
30
30
|
require('./install/cookie-parser1')(core);
|
|
31
31
|
require('./install/formidable1')(core);
|
|
32
32
|
require('./install/http')(core);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -29,23 +29,23 @@ const INPUT_TYPES = {
|
|
|
29
29
|
module.exports = function init(core) {
|
|
30
30
|
const { assess, depHooks, logger, patcher, scopes } = core;
|
|
31
31
|
|
|
32
|
-
const
|
|
32
|
+
const preHook = (data) => {
|
|
33
33
|
const [req, , next] = data.args;
|
|
34
34
|
data.args[2] = scopes.wrap(function contrastNext(...args) {
|
|
35
35
|
const sourceContext = scopes.sources.getStore()?.assess;
|
|
36
36
|
|
|
37
37
|
if (!sourceContext) {
|
|
38
|
-
logger.error({
|
|
38
|
+
logger.error({ funcKey: data.funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
39
39
|
return next(...args);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (sourceContext.parsedBody) {
|
|
43
|
-
logger.trace({
|
|
43
|
+
logger.trace({ funcKey: data.funcKey }, 'values already tracked');
|
|
44
44
|
return next(...args);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// when using a specific parser, we know the input type.
|
|
48
|
-
let inputType = INPUT_TYPES[name];
|
|
48
|
+
let inputType = INPUT_TYPES[data.name];
|
|
49
49
|
// when using `bodyParser()`, determine input type by content type.
|
|
50
50
|
if (!inputType) {
|
|
51
51
|
inputType = req.headers?.['content-type']?.includes('json')
|
|
@@ -71,7 +71,7 @@ module.exports = function init(core) {
|
|
|
71
71
|
assess.dataflow.sources.handle({
|
|
72
72
|
context,
|
|
73
73
|
data: _data,
|
|
74
|
-
name,
|
|
74
|
+
name: data.name,
|
|
75
75
|
keys,
|
|
76
76
|
inputType,
|
|
77
77
|
sourceContext,
|
|
@@ -82,7 +82,7 @@ module.exports = function init(core) {
|
|
|
82
82
|
|
|
83
83
|
sourceContext.parsedBody = !!Object.keys(_data).length;
|
|
84
84
|
} catch (err) {
|
|
85
|
-
logger.error({
|
|
85
|
+
logger.error({ err, funcKey: data.funcKey }, 'unable to handle source');
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
return next(...args);
|
|
@@ -99,11 +99,10 @@ module.exports = function init(core) {
|
|
|
99
99
|
name: 'body-parser',
|
|
100
100
|
patchType,
|
|
101
101
|
post(data) {
|
|
102
|
-
const name = 'body-parser.bodyParser';
|
|
103
102
|
data.result = patcher.patch(data.result, {
|
|
104
|
-
name,
|
|
103
|
+
name: 'body-parser.bodyParser',
|
|
105
104
|
patchType,
|
|
106
|
-
pre:
|
|
105
|
+
pre: preHook,
|
|
107
106
|
});
|
|
108
107
|
},
|
|
109
108
|
});
|
|
@@ -113,11 +112,10 @@ module.exports = function init(core) {
|
|
|
113
112
|
name: `body-parser.${method}`,
|
|
114
113
|
patchType,
|
|
115
114
|
post(data) {
|
|
116
|
-
const name = `body-parser.${method}.${method}Parser`;
|
|
117
115
|
data.result = patcher.patch(data.result, {
|
|
118
|
-
name
|
|
116
|
+
name: `body-parser.${method}.${method}Parser`,
|
|
119
117
|
patchType,
|
|
120
|
-
pre:
|
|
118
|
+
pre: preHook
|
|
121
119
|
});
|
|
122
120
|
},
|
|
123
121
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
19
|
const { patchType } = require('../common');
|
|
20
20
|
|
|
21
|
+
const inputType = InputType.MULTIPART_VALUE;
|
|
22
|
+
const name = 'busboy';
|
|
23
|
+
|
|
21
24
|
module.exports = (core) => {
|
|
22
25
|
const {
|
|
23
26
|
depHooks,
|
|
@@ -26,21 +29,18 @@ module.exports = (core) => {
|
|
|
26
29
|
assess: { dataflow: { sources } },
|
|
27
30
|
} = core;
|
|
28
31
|
|
|
29
|
-
const name = 'busboy';
|
|
30
|
-
|
|
31
32
|
function createPreHook(finalEventName) {
|
|
32
|
-
return function(data) {
|
|
33
|
-
const { orig, hooked } = data;
|
|
33
|
+
return function (data) {
|
|
34
|
+
const { orig, hooked, funcKey } = data;
|
|
34
35
|
const sourceContext = core.scopes.sources.getStore()?.assess;
|
|
35
|
-
const inputType = InputType.MULTIPART_VALUE;
|
|
36
36
|
|
|
37
37
|
if (!sourceContext) {
|
|
38
|
-
logger.error({ inputType,
|
|
38
|
+
logger.error({ inputType, funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (sourceContext.parsedBody) {
|
|
43
|
-
logger.trace({ inputType,
|
|
43
|
+
logger.trace({ inputType, funcKey }, 'values already tracked');
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -67,7 +67,7 @@ module.exports = (core) => {
|
|
|
67
67
|
data.args[2] = obj[fieldName];
|
|
68
68
|
sourceContext.busboyParsedBody = true;
|
|
69
69
|
} catch (err) {
|
|
70
|
-
logger.error({ err, inputType,
|
|
70
|
+
logger.error({ err, inputType, funcKey }, 'unable to handle source');
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -88,8 +88,8 @@ module.exports = (core) => {
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
depHooks.resolve({ name, version: '>=1.0.0' }, (busboy) =>
|
|
92
|
-
busboy, {
|
|
91
|
+
depHooks.resolve({ name, version: '>=1.0.0' }, (busboy) =>
|
|
92
|
+
patcher.patch(busboy, {
|
|
93
93
|
name,
|
|
94
94
|
patchType,
|
|
95
95
|
post(data) {
|
|
@@ -99,14 +99,14 @@ module.exports = (core) => {
|
|
|
99
99
|
pre: createPreHook('close')
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
|
-
}
|
|
103
|
-
)
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
const
|
|
106
|
+
const busboyInstrumentation = sources.busboyInstrumentation = {
|
|
107
107
|
install
|
|
108
108
|
};
|
|
109
109
|
|
|
110
|
-
return
|
|
110
|
+
return busboyInstrumentation;
|
|
111
111
|
};
|
|
112
112
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -36,17 +36,18 @@ module.exports = function init(core) {
|
|
|
36
36
|
name,
|
|
37
37
|
patchType,
|
|
38
38
|
pre(data) {
|
|
39
|
+
const { funcKey } = data;
|
|
39
40
|
const [req, , next] = data.args;
|
|
40
41
|
data.args[2] = function contrastNext(...args) {
|
|
41
42
|
const sourceContext = scopes.sources.getStore()?.assess;
|
|
42
43
|
|
|
43
44
|
if (!sourceContext) {
|
|
44
|
-
logger.error({
|
|
45
|
+
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
if (sourceContext.parsedCookies) {
|
|
49
|
-
logger.trace({
|
|
50
|
+
logger.trace({ funcKey }, 'cookies already tracked');
|
|
50
51
|
} else if (req.cookies) {
|
|
51
52
|
try {
|
|
52
53
|
assess.dataflow.sources.handle({
|
|
@@ -62,12 +63,12 @@ module.exports = function init(core) {
|
|
|
62
63
|
|
|
63
64
|
sourceContext.parsedCookies = !!Object.keys(req.cookies).length;
|
|
64
65
|
} catch (err) {
|
|
65
|
-
logger.error({
|
|
66
|
+
logger.error({ err, funcKey }, 'unable to handle source');
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
if (sourceContext.parsedSignedCookies) {
|
|
70
|
-
logger.trace({
|
|
71
|
+
logger.trace({ funcKey }, 'signedCookies already tracked');
|
|
71
72
|
} else if (req.signedCookies) {
|
|
72
73
|
try {
|
|
73
74
|
assess.dataflow.sources.handle({
|
|
@@ -83,7 +84,7 @@ module.exports = function init(core) {
|
|
|
83
84
|
|
|
84
85
|
sourceContext.parsedSignedCookies = !!Object.keys(req.signedCookies).length;
|
|
85
86
|
} catch (err) {
|
|
86
|
-
logger.error({
|
|
87
|
+
logger.error({ err, funcKey }, 'unable to handle source');
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
-
const { patchType } = require('
|
|
19
|
+
const { patchType } = require('../../common');
|
|
20
20
|
|
|
21
21
|
module.exports = function init(core) {
|
|
22
22
|
const { depHooks, patcher, logger } = core;
|
|
@@ -30,25 +30,24 @@ module.exports = function init(core) {
|
|
|
30
30
|
patcher.patch(Layer.prototype, 'match', {
|
|
31
31
|
name,
|
|
32
32
|
patchType,
|
|
33
|
-
post(
|
|
34
|
-
const layer = data.obj;
|
|
33
|
+
post({ obj: layer, result, orig, hooked, funcKey }) {
|
|
35
34
|
|
|
36
35
|
// we can exit early if
|
|
37
36
|
// the layer doesn't match the request or
|
|
38
37
|
// the layer doesn't recognize any parameters
|
|
39
|
-
if (!
|
|
38
|
+
if (!result || !layer.keys || layer.keys.length === 0) {
|
|
40
39
|
return;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
const sourceContext = core.scopes.sources.getStore()?.assess;
|
|
44
43
|
|
|
45
44
|
if (!sourceContext) {
|
|
46
|
-
logger.error({
|
|
45
|
+
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
47
46
|
return;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
if (sourceContext.parsedParams) {
|
|
51
|
-
logger.trace({
|
|
50
|
+
logger.trace({ funcKey }, 'values already tracked');
|
|
52
51
|
return;
|
|
53
52
|
}
|
|
54
53
|
|
|
@@ -58,15 +57,15 @@ module.exports = function init(core) {
|
|
|
58
57
|
name,
|
|
59
58
|
inputType: InputType.PARAMETER_VALUE,
|
|
60
59
|
stacktraceOpts: {
|
|
61
|
-
constructorOpt:
|
|
62
|
-
prependFrames: [
|
|
60
|
+
constructorOpt: hooked,
|
|
61
|
+
prependFrames: [orig]
|
|
63
62
|
},
|
|
64
63
|
data: layer.params,
|
|
65
64
|
sourceContext
|
|
66
65
|
});
|
|
67
66
|
sourceContext.parsedParams = true;
|
|
68
67
|
} catch (err) {
|
|
69
|
-
logger.error({ err,
|
|
68
|
+
logger.error({ err, funcKey }, 'unable to handle source');
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright:
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
3
|
* Contact: support@contrastsecurity.com
|
|
4
4
|
* License: Commercial
|
|
5
5
|
|
|
@@ -31,9 +31,8 @@ module.exports = function (core) {
|
|
|
31
31
|
depHooks.resolve({ name: 'fastify', version: '>=3.0.0' }, (fastify) => patcher.patch(fastify, {
|
|
32
32
|
name: 'fastify.constructor',
|
|
33
33
|
patchType,
|
|
34
|
-
post({ result: server }) {
|
|
34
|
+
post({ result: server, funcKey }) {
|
|
35
35
|
server.addHook('preValidation', function preValidationHandler(request, reply, done) {
|
|
36
|
-
const name = 'fastify.preValidation';
|
|
37
36
|
const bodyType = request?.headers?.['content-type']?.includes('/json')
|
|
38
37
|
? InputType.JSON_VALUE
|
|
39
38
|
: typeof request.body == 'object'
|
|
@@ -42,7 +41,7 @@ module.exports = function (core) {
|
|
|
42
41
|
const sourceContext = core.scopes.sources.getStore()?.assess;
|
|
43
42
|
|
|
44
43
|
if (!sourceContext) {
|
|
45
|
-
logger.error({
|
|
44
|
+
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
46
45
|
return;
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -52,7 +51,7 @@ module.exports = function (core) {
|
|
|
52
51
|
{ key: 'body', inputType: bodyType, alreadyTrackedFlag: 'parsedBody' }
|
|
53
52
|
].forEach(({ key, inputType, alreadyTrackedFlag }) => {
|
|
54
53
|
if (sourceContext[alreadyTrackedFlag]) {
|
|
55
|
-
logger.trace({ inputType,
|
|
54
|
+
logger.trace({ inputType, funcKey }, 'values already tracked');
|
|
56
55
|
return;
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -61,14 +60,14 @@ module.exports = function (core) {
|
|
|
61
60
|
context: `req.${key}`,
|
|
62
61
|
data: request[key],
|
|
63
62
|
inputType,
|
|
64
|
-
name,
|
|
63
|
+
name: 'fastify.preValidation',
|
|
65
64
|
stacktraceOpts: {
|
|
66
65
|
constructorOpt: preValidationHandler,
|
|
67
66
|
},
|
|
68
67
|
sourceContext
|
|
69
68
|
});
|
|
70
69
|
} catch (err) {
|
|
71
|
-
logger.error({ err, inputType,
|
|
70
|
+
logger.error({ err, inputType, funcKey }, 'unable to handle Fastify source');
|
|
72
71
|
}
|
|
73
72
|
});
|
|
74
73
|
|