@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
|
@@ -20,7 +20,7 @@ Copyright: 2022 Contrast Security, Inc
|
|
|
20
20
|
|
|
21
21
|
const _ = require('lodash');
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const { IMPORTANCE } = require('../constants');
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Compares two findings and returns the one which is
|
|
@@ -38,31 +38,26 @@ const rankEffectiveness = (a, b) => {
|
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
return
|
|
41
|
+
// effective is a boolean, so there is no "higher" effectiveness.
|
|
42
|
+
return a.sample.effective ? a : b;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* Compares two findings and returns the one which
|
|
47
|
-
*
|
|
48
|
-
* assessment score is the same, <code>null</code> is
|
|
49
|
-
* returned, signifying that a ranking order cannot be
|
|
50
|
-
* determined for this criteria.
|
|
46
|
+
* Compares two findings and returns the one which has the highest
|
|
47
|
+
* score. If their scores are the same, return the first finding.
|
|
51
48
|
* @param {object} a First finding
|
|
52
49
|
* @param {object} b Second finding
|
|
53
|
-
* @returns {object
|
|
50
|
+
* @returns {object}
|
|
54
51
|
*/
|
|
55
|
-
const
|
|
56
|
-
const p1 = _.get(a, POINTS_PATH);
|
|
57
|
-
const p2 = _.get(b, POINTS_PATH);
|
|
52
|
+
const POINTS_PATH = 'sample.assessment.results.points';
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
54
|
+
function rankPoints(a, b) {
|
|
55
|
+
const pA = _.get(a, POINTS_PATH);
|
|
56
|
+
const pB = _.get(b, POINTS_PATH);
|
|
63
57
|
|
|
64
|
-
return
|
|
65
|
-
|
|
58
|
+
// return a if a is greater than or equal to b
|
|
59
|
+
return pA < pB ? b : a;
|
|
60
|
+
}
|
|
66
61
|
|
|
67
62
|
/**
|
|
68
63
|
* Ranks two findings against effectiveness and score.
|
|
@@ -72,64 +67,77 @@ const rankPoints = (a, b) => {
|
|
|
72
67
|
* @param {object} b Second finding
|
|
73
68
|
* @returns {object} The highest-ranked finding
|
|
74
69
|
*/
|
|
75
|
-
const rankFindings = (a, b) => rankEffectiveness(a, b) || rankPoints(a, b)
|
|
70
|
+
const rankFindings = (a, b) => rankEffectiveness(a, b) || rankPoints(a, b);
|
|
76
71
|
|
|
77
72
|
/**
|
|
78
|
-
* Takes a collection of findings and organizes them into
|
|
79
|
-
*
|
|
80
|
-
*
|
|
73
|
+
* Takes a collection of findings and organizes them into a map having keys
|
|
74
|
+
* being unique input types and paths, and values being unique findings pertaining
|
|
75
|
+
* to each key.
|
|
81
76
|
* @param {object} memo The map being created
|
|
82
77
|
* @param {object} finding Current finding in iteratee
|
|
83
78
|
* @returns {object} Map of ranked findings per type/path
|
|
84
79
|
*/
|
|
85
|
-
|
|
80
|
+
function rankIntoMap(memo, finding) {
|
|
86
81
|
const type = _.get(finding, 'sample.input.type', '_');
|
|
87
82
|
const path = _.get(finding, 'sample.input.documentPath', '_');
|
|
88
83
|
const name = _.get(finding, 'sample.input.name', '_');
|
|
89
84
|
|
|
90
|
-
|
|
85
|
+
// this string is the key to the map
|
|
91
86
|
const memoPath = `${type}.${path}.${name}`;
|
|
92
|
-
const existing = memo[memoPath];
|
|
93
87
|
|
|
94
|
-
memo[memoPath]
|
|
88
|
+
const existing = memo[memoPath];
|
|
89
|
+
// if it exists, rank it against the new finding
|
|
90
|
+
memo[memoPath] = existing ? rankFindings(existing, finding) : finding;
|
|
95
91
|
|
|
92
|
+
// memo returned despite having side effects because this function is
|
|
93
|
+
// called using reduce.
|
|
96
94
|
return memo;
|
|
97
|
-
}
|
|
95
|
+
}
|
|
98
96
|
|
|
99
97
|
/**
|
|
100
|
-
*
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*
|
|
104
|
-
* collection without low-scoring samples. Low-scoring
|
|
105
|
-
* samples are not confirmed attacks. BUT, we DO want to
|
|
106
|
-
* report on findings if they were effective, always.
|
|
107
|
-
* @param {object[]} findings
|
|
108
|
-
* @returns {object[]}
|
|
109
|
-
*/
|
|
110
|
-
const filterLowScoring = (findings = []) =>
|
|
111
|
-
_.filter(
|
|
112
|
-
findings,
|
|
113
|
-
(finding) =>
|
|
114
|
-
// Virtual Patch findings do not have inputs but always create a WW sample.
|
|
115
|
-
// Make sure they were effective.
|
|
116
|
-
(!finding.sample.input && finding.sample.effective) ||
|
|
117
|
-
/* Don't include low-scoring ineffective attacks. */
|
|
118
|
-
!(!finding.sample.effective && !finding.sample.confirmedAttack)
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Accepts a collection of findings and returns a new
|
|
123
|
-
* collection whose samples are unique with respect to
|
|
124
|
-
* input type and path of the finding per input type. Any
|
|
125
|
-
* duplicate findings for the same type and path will be
|
|
126
|
-
* filtered to only include the one with the highest
|
|
127
|
-
* points/effectiveness ranking.
|
|
98
|
+
* Accepts a collection of findings and returns a new collection whose samples
|
|
99
|
+
* are unique with respect to input type and path of the finding per input type.
|
|
100
|
+
* Any duplicate findings for the same type and path will be filtered to only
|
|
101
|
+
* include the one with the highest points/effectiveness ranking.
|
|
128
102
|
* @param {object[]} findings The findings to aggregate.
|
|
103
|
+
* @param {function} wwFilter filter to check if a sample should be saved.
|
|
129
104
|
* @returns {object[]}
|
|
105
|
+
*
|
|
106
|
+
* effective, but not blocked, becomes PROBED.
|
|
107
|
+
*
|
|
130
108
|
*/
|
|
131
|
-
|
|
132
|
-
|
|
109
|
+
function aggregate(findings, wwFilter) {
|
|
110
|
+
// separate the findings into effective and ineffective
|
|
111
|
+
// but marked as worth-watching by agent-lib. if not in
|
|
112
|
+
// one of the two lists, the finding is not relevant.
|
|
113
|
+
const effective = [];
|
|
114
|
+
const wwFindings = [];
|
|
115
|
+
// and the rest were not agent-lib worth-watching or effective
|
|
116
|
+
for (const finding of findings) {
|
|
117
|
+
const { sample } = finding;
|
|
118
|
+
if (sample.confirmedAttack || sample.effective) {
|
|
119
|
+
effective.push(finding);
|
|
120
|
+
} else if (finding.rule.agentLibBit && sample.assessment.results.importance === IMPORTANCE.WORTH_WATCHING) {
|
|
121
|
+
//console.log(finding.rule.id, s.results)
|
|
122
|
+
wwFindings.push(finding);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// do we need to run any inputs through the full scoring (not the abbreviated
|
|
127
|
+
// worth-watching scoring)?
|
|
128
|
+
if (wwFindings.length) {
|
|
129
|
+
for (const finding of wwFindings) {
|
|
130
|
+
if (wwFilter(finding)) {
|
|
131
|
+
finding.sample.assessment.results.importance = IMPORTANCE.DEFINITE;
|
|
132
|
+
// put this in the "effective list", even though it wasn't effective, so it
|
|
133
|
+
// will be reported as PROBED.
|
|
134
|
+
effective.push(finding);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return _.values(effective.reduce(rankIntoMap, {}));
|
|
140
|
+
}
|
|
133
141
|
|
|
134
142
|
module.exports = {
|
|
135
143
|
aggregate
|