@contrast/agent 4.12.1 → 4.13.1
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/bootstrap.js +2 -3
- package/esm.mjs +9 -35
- package/lib/assess/membrane/debraner.js +0 -2
- package/lib/assess/membrane/index.js +1 -3
- package/lib/assess/models/base-event.js +1 -1
- package/lib/assess/models/tag-range/util.js +1 -2
- package/lib/assess/policy/util.js +3 -2
- package/lib/assess/propagators/JSON/stringify.js +6 -11
- package/lib/assess/propagators/ajv/conditionals.js +0 -3
- package/lib/assess/propagators/ajv/json-schema-type-evaluators.js +5 -4
- package/lib/assess/propagators/ajv/refs.js +1 -2
- package/lib/assess/propagators/ajv/schema-context.js +2 -3
- package/lib/assess/propagators/path/common.js +38 -29
- package/lib/assess/propagators/path/resolve.js +1 -0
- package/lib/assess/propagators/sequelize/utils.js +1 -2
- package/lib/assess/propagators/v8/init-hooks.js +0 -1
- package/lib/assess/sinks/dynamo.js +65 -30
- package/lib/assess/static/hardcoded.js +3 -3
- package/lib/assess/static/read-findings-from-cache.js +40 -0
- package/lib/assess/technologies/index.js +12 -13
- package/lib/cli-rewriter/index.js +65 -6
- package/lib/core/config/options.js +6 -0
- package/lib/core/config/util.js +15 -33
- package/lib/core/exclusions/input.js +6 -1
- package/lib/core/express/index.js +2 -4
- package/lib/core/logger/debug-logger.js +2 -2
- package/lib/core/stacktrace.js +2 -1
- package/lib/hooks/http.js +81 -81
- package/lib/hooks/require.js +1 -0
- package/lib/instrumentation.js +17 -0
- package/lib/protect/analysis/aho-corasick.js +1 -1
- package/lib/protect/errors/handler-async-errors.js +66 -0
- package/lib/protect/input-analysis.js +7 -13
- package/lib/protect/listeners.js +27 -23
- package/lib/protect/rules/base-scanner/index.js +2 -2
- package/lib/protect/rules/bot-blocker/bot-blocker-rule.js +4 -2
- package/lib/protect/rules/cmd-injection/cmdinjection-rule.js +57 -2
- package/lib/protect/rules/cmd-injection-semantic-chained-commands/cmd-injection-semantic-chained-commands-rule.js +31 -2
- package/lib/protect/rules/cmd-injection-semantic-dangerous-paths/cmd-injection-semantic-dangerous-paths-rule.js +32 -2
- package/lib/protect/rules/index.js +42 -21
- package/lib/protect/rules/ip-denylist/ip-denylist-rule.js +2 -2
- package/lib/protect/rules/nosqli/nosql-injection-rule.js +104 -39
- package/lib/protect/rules/path-traversal/path-traversal-rule.js +3 -0
- package/lib/protect/rules/rule-factory.js +6 -7
- package/lib/protect/rules/signatures/signature.js +3 -0
- package/lib/protect/rules/sqli/sql-injection-rule.js +98 -5
- package/lib/protect/rules/sqli/sql-scanner/labels.json +0 -3
- package/lib/protect/rules/xss/reflected-xss-rule.js +3 -3
- package/lib/protect/sample-aggregator.js +65 -57
- package/lib/protect/service.js +709 -104
- package/lib/reporter/models/app-activity/sample.js +6 -0
- package/lib/reporter/speedracer/unknown-connection-state.js +20 -32
- package/lib/reporter/translations/to-protobuf/settings/assess-features.js +4 -6
- package/lib/reporter/ts-reporter.js +1 -1
- package/lib/util/get-file-type.js +43 -0
- package/package.json +10 -11
- package/perf-logs.js +2 -5
|
@@ -39,6 +39,12 @@ class Sample {
|
|
|
39
39
|
this.input = input;
|
|
40
40
|
this.request = appContext.request;
|
|
41
41
|
|
|
42
|
+
// extra info for processing at sink time.
|
|
43
|
+
// NOT TO BE INCLUDED IN ACTUAL DTM AT REPORTING TIME.
|
|
44
|
+
// This is particularly useful when using the agent lib for processing
|
|
45
|
+
// mongo expansion and injection.
|
|
46
|
+
this._inputInfoForSink = {};
|
|
47
|
+
|
|
42
48
|
this.assessment = assessment;
|
|
43
49
|
|
|
44
50
|
if (assessment) {
|
|
@@ -46,28 +46,23 @@ class UnknownConnectionState extends BaseConnectionState {
|
|
|
46
46
|
* @param {SpeedracerBaseMessage} message
|
|
47
47
|
* @returns {Promise}
|
|
48
48
|
*/
|
|
49
|
-
send(message) {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
async send(message) {
|
|
50
|
+
try {
|
|
51
|
+
const clientResponse = await super.send(message);
|
|
52
|
+
this.speedracer.transitionConnectionState(SUCCESS);
|
|
53
|
+
return clientResponse;
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// See if we need to start or wait for service
|
|
52
56
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
await this.handleSendFailure(err);
|
|
58
|
+
await this.retryInitialization();
|
|
59
|
+
const result = await this.speedracer.send(message);
|
|
60
|
+
return result;
|
|
56
61
|
} catch (err) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
await this.handleSendFailure(err);
|
|
60
|
-
await this.retryInitialization();
|
|
61
|
-
// eslint-disable-next-line prettier/prettier
|
|
62
|
-
speedracer.send(message)
|
|
63
|
-
.then((r) => resolve(r))
|
|
64
|
-
.catch((e) => reject(e));
|
|
65
|
-
} catch (err) {
|
|
66
|
-
speedracer.transitionConnectionState(FAILURE);
|
|
67
|
-
reject(err);
|
|
68
|
-
}
|
|
62
|
+
this.speedracer.transitionConnectionState(FAILURE);
|
|
63
|
+
throw err;
|
|
69
64
|
}
|
|
70
|
-
}
|
|
65
|
+
}
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
/**
|
|
@@ -106,25 +101,18 @@ class UnknownConnectionState extends BaseConnectionState {
|
|
|
106
101
|
* messages.
|
|
107
102
|
* @returns {Promise}
|
|
108
103
|
*/
|
|
109
|
-
retryInitialization() {
|
|
104
|
+
async retryInitialization() {
|
|
110
105
|
const startup = this.speedracer.messageCache.get('startup');
|
|
111
106
|
const appcreate = this.speedracer.messageCache.get('appcreate');
|
|
112
107
|
|
|
113
108
|
if (!startup || !appcreate) return Promise.resolve();
|
|
114
109
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
);
|
|
110
|
+
this.speedracer.logger.debug(
|
|
111
|
+
'Sending initialization messages to service'
|
|
112
|
+
);
|
|
119
113
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
await this.speedracer.send(appcreate);
|
|
123
|
-
resolve();
|
|
124
|
-
} catch (err) {
|
|
125
|
-
reject(err);
|
|
126
|
-
}
|
|
127
|
-
});
|
|
114
|
+
await this.speedracer.send(startup);
|
|
115
|
+
await this.speedracer.send(appcreate);
|
|
128
116
|
}
|
|
129
117
|
|
|
130
118
|
/**
|
|
@@ -36,7 +36,6 @@ function AssessFeatures({
|
|
|
36
36
|
validatorScopes,
|
|
37
37
|
validators = []
|
|
38
38
|
} = {}) {
|
|
39
|
-
/* eslint-disable no-sparse-arrays, prettier/prettier */
|
|
40
39
|
return new settings.AssessFeatures([
|
|
41
40
|
enabled, // 1 enabled
|
|
42
41
|
dynamicSources, // 2 dynamic_sources
|
|
@@ -52,13 +51,12 @@ function AssessFeatures({
|
|
|
52
51
|
validators.map(CustomRuleFeature).map(v => v.array), // 12 validators
|
|
53
52
|
disabledRules, // 13 disabled_rules (deprecated)
|
|
54
53
|
Sampling(sampling).array, // 14 sampling
|
|
55
|
-
, //
|
|
56
|
-
, //
|
|
57
|
-
, //
|
|
58
|
-
, //
|
|
54
|
+
undefined, // 15 -
|
|
55
|
+
undefined, // 16 -
|
|
56
|
+
undefined, // 17 -
|
|
57
|
+
undefined, // 18 -
|
|
59
58
|
[] // 19 dynamic_sources_map
|
|
60
59
|
]);
|
|
61
|
-
/* eslint-enable */
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
function AssessStacktrace(stacktraces) {
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const parent = require('parent-package-json');
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line complexity
|
|
21
|
+
function getType(filename) {
|
|
22
|
+
if (filename.startsWith('node:')) {
|
|
23
|
+
return 'builtin';
|
|
24
|
+
}
|
|
25
|
+
filename = filename.replace('file://', '');
|
|
26
|
+
|
|
27
|
+
let parentType = 'commonjs';
|
|
28
|
+
try {
|
|
29
|
+
parentType = parent(filename).parse().type;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
// Node assumes `commonjs ` if there's no `type` set in package.json
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const ext = path.extname(filename);
|
|
35
|
+
if (ext === '.mjs' || (ext === '.js' && parentType === 'module')) {
|
|
36
|
+
return 'module';
|
|
37
|
+
} else if (ext === '.cjs' || (ext === '.js' && parentType !== 'module')) {
|
|
38
|
+
return 'commonjs';
|
|
39
|
+
}
|
|
40
|
+
return 'unknown';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = getType;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/agent",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.1",
|
|
4
4
|
"description": "Node.js security instrumentation by Contrast Security",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"security",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
31
|
"docs": "jsdoc -c ../.jsdoc.json",
|
|
32
|
-
"release": "scripts/make-release.js",
|
|
33
|
-
"tag": "scripts/tag-release.js",
|
|
32
|
+
"release": "node scripts/make-release.js",
|
|
33
|
+
"tag": "node scripts/tag-release.js",
|
|
34
34
|
"test:debug": "scripts/test.sh debug",
|
|
35
35
|
"test": "scripts/test.sh",
|
|
36
36
|
"test:screener": "mocha --parallel test/screener/**/*test.js",
|
|
@@ -76,12 +76,13 @@
|
|
|
76
76
|
"@babel/template": "^7.10.4",
|
|
77
77
|
"@babel/traverse": "^7.12.1",
|
|
78
78
|
"@babel/types": "^7.12.1",
|
|
79
|
+
"@contrast/agent-lib": "^2.2.3",
|
|
79
80
|
"@contrast/distringuish-prebuilt": "^2.2.0",
|
|
80
81
|
"@contrast/flat": "^4.1.1",
|
|
81
82
|
"@contrast/fn-inspect": "^2.4.4",
|
|
82
83
|
"@contrast/heapdump": "^1.1.0",
|
|
83
84
|
"@contrast/protobuf-api": "^3.2.3",
|
|
84
|
-
"@contrast/require-hook": "^
|
|
85
|
+
"@contrast/require-hook": "^3.0.0",
|
|
85
86
|
"@contrast/synchronous-source-maps": "^1.1.0",
|
|
86
87
|
"amqp-connection-manager": "^3.2.2",
|
|
87
88
|
"amqplib": "^0.8.0",
|
|
@@ -116,14 +117,14 @@
|
|
|
116
117
|
"devDependencies": {
|
|
117
118
|
"@aws-sdk/client-dynamodb": "^3.39.0",
|
|
118
119
|
"@bmacnaughton/string-generator": "^1.0.0",
|
|
119
|
-
"@contrast/eslint-config": "^3.0.0
|
|
120
|
+
"@contrast/eslint-config": "^3.0.0",
|
|
120
121
|
"@contrast/fake-module": "file:test/mock/contrast-fake",
|
|
121
122
|
"@contrast/screener-service": "^1.12.9",
|
|
122
123
|
"@hapi/boom": "file:test/mock/boom",
|
|
123
124
|
"@hapi/hapi": "file:test/mock/hapi",
|
|
124
125
|
"@ls-lint/ls-lint": "^1.8.1",
|
|
125
|
-
"@typescript-eslint/eslint-plugin": "^5.12.
|
|
126
|
-
"@typescript-eslint/parser": "^5.12.
|
|
126
|
+
"@typescript-eslint/eslint-plugin": "^5.12.1",
|
|
127
|
+
"@typescript-eslint/parser": "^5.12.1",
|
|
127
128
|
"ajv": "^8.5.0",
|
|
128
129
|
"ast-types": "^0.12.4",
|
|
129
130
|
"aws-sdk": "file:test/mock/aws-sdk",
|
|
@@ -141,10 +142,8 @@
|
|
|
141
142
|
"ejs": "^3.1.6",
|
|
142
143
|
"escape-html": "^1.0.3",
|
|
143
144
|
"eslint": "^8.9.0",
|
|
144
|
-
"eslint-config-prettier": "^8.3.0",
|
|
145
145
|
"eslint-plugin-mocha": "^10.0.3",
|
|
146
146
|
"eslint-plugin-node": "^11.1.0",
|
|
147
|
-
"eslint-plugin-prettier": "^4.0.0",
|
|
148
147
|
"express": "file:test/mock/express",
|
|
149
148
|
"fetch-cookie": "^0.11.0",
|
|
150
149
|
"form-data": "^3.0.0",
|
|
@@ -161,6 +160,7 @@
|
|
|
161
160
|
"marsdb": "file:test/mock/marsdb",
|
|
162
161
|
"mocha": "^9.2.0",
|
|
163
162
|
"mochawesome": "^7.0.1",
|
|
163
|
+
"mock-fs": "^5.1.2",
|
|
164
164
|
"mongodb": "file:test/mock/mongodb",
|
|
165
165
|
"mongodb-npm": "npm:mongodb@^3.6.5",
|
|
166
166
|
"mongoose": "^6.1.1",
|
|
@@ -173,13 +173,12 @@
|
|
|
173
173
|
"nyc": "^15.1.0",
|
|
174
174
|
"pg": "file:test/mock/pg",
|
|
175
175
|
"pino": "^6.7.0",
|
|
176
|
-
"prettier": "^2.5.1",
|
|
177
176
|
"proxyquire": "^2.1.0",
|
|
178
177
|
"qs": "^6.9.4",
|
|
179
178
|
"rethinkdb": "file:test/mock/rethinkdb",
|
|
180
179
|
"sequelize": "^6.11.0",
|
|
181
180
|
"shellcheck": "^1.0.0",
|
|
182
|
-
"sinon": "^
|
|
181
|
+
"sinon": "^9.2.4",
|
|
183
182
|
"sinon-chai": "^3.3.0",
|
|
184
183
|
"sqlite3": "file:test/mock/sqlite3",
|
|
185
184
|
"swig": "file:test/mock/swig",
|
package/perf-logs.js
CHANGED
|
@@ -104,7 +104,6 @@ async function processFile(filename, filter, group) {
|
|
|
104
104
|
continue;
|
|
105
105
|
}
|
|
106
106
|
if (!group) {
|
|
107
|
-
// eslint-disable-next-line no-console
|
|
108
107
|
console.log(JSON.stringify(data, null, 4));
|
|
109
108
|
} else {
|
|
110
109
|
const key = filter
|
|
@@ -125,7 +124,6 @@ async function processFile(filename, filter, group) {
|
|
|
125
124
|
}
|
|
126
125
|
|
|
127
126
|
if (group) {
|
|
128
|
-
// eslint-disable-next-line no-console
|
|
129
127
|
console.log(JSON.stringify(Object.values(merged), null, 4));
|
|
130
128
|
}
|
|
131
129
|
}
|
|
@@ -148,10 +146,9 @@ if (program.filter) {
|
|
|
148
146
|
try {
|
|
149
147
|
filterRegex = new RegExp(program.filter);
|
|
150
148
|
} catch (e) {
|
|
151
|
-
// eslint-disable-next-line no-console
|
|
152
149
|
console.error('invalid filter regex');
|
|
153
|
-
// eslint-disable-
|
|
154
|
-
|
|
150
|
+
process.exit(-1); // eslint-disable-line no-process-exit
|
|
151
|
+
|
|
155
152
|
}
|
|
156
153
|
}
|
|
157
154
|
|