@contrast/agent 4.5.1 → 4.7.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/bin/VERSION +1 -1
- package/bin/linux/contrast-service +0 -0
- package/bin/mac/contrast-service +0 -0
- package/bin/windows/contrast-service.exe +0 -0
- package/lib/assess/membrane/deserialization-membrane.js +4 -5
- package/lib/assess/membrane/source-membrane.js +16 -33
- package/lib/assess/models/call-context.js +1 -1
- package/lib/assess/policy/propagators.json +19 -21
- package/lib/assess/policy/rules.json +7 -2
- package/lib/assess/policy/signatures.json +42 -0
- package/lib/assess/policy/util.js +2 -1
- package/lib/assess/propagators/JSON/parse.js +1 -1
- package/lib/assess/propagators/JSON/stringify.js +3 -3
- package/lib/assess/propagators/array-prototype-join.js +7 -8
- package/lib/assess/propagators/common.js +7 -5
- package/lib/assess/propagators/dustjs/escape-html.js +22 -0
- package/lib/assess/propagators/dustjs/escape-js.js +22 -0
- package/lib/assess/propagators/encode-uri/encode-uri-component.js +22 -0
- package/lib/assess/propagators/encode-uri/encode-uri.js +22 -0
- package/lib/assess/propagators/handlebars-escape-expresssion.js +1 -1
- package/lib/assess/propagators/index.js +0 -2
- package/lib/assess/propagators/joi/boolean.js +1 -1
- package/lib/assess/propagators/joi/expression.js +1 -1
- package/lib/assess/propagators/joi/number.js +1 -1
- package/lib/assess/propagators/joi/string-base.js +1 -1
- package/lib/assess/propagators/joi/string-schema.js +12 -13
- package/lib/assess/propagators/joi/values.js +37 -22
- package/lib/assess/propagators/manager.js +12 -10
- package/lib/assess/propagators/mongoose/helpers.js +20 -0
- package/lib/assess/propagators/mongoose/index.js +18 -0
- package/lib/assess/propagators/mongoose/map.js +74 -0
- package/lib/assess/propagators/mongoose/string.js +104 -0
- package/lib/assess/propagators/mustache/escape.js +22 -0
- package/lib/assess/propagators/number.js +54 -0
- package/lib/assess/propagators/object.js +6 -7
- package/lib/assess/propagators/path/basename.js +14 -13
- package/lib/assess/propagators/path/common.js +156 -47
- package/lib/assess/propagators/path/dirname.js +14 -13
- package/lib/assess/propagators/path/extname.js +14 -13
- package/lib/assess/propagators/path/join.js +5 -1
- package/lib/assess/propagators/path/normalize.js +1 -2
- package/lib/assess/propagators/path/parse.js +1 -1
- package/lib/assess/propagators/path/relative.js +7 -5
- package/lib/assess/propagators/path/resolve.js +11 -2
- package/lib/assess/propagators/querystring/escape.js +20 -18
- package/lib/assess/propagators/querystring/parse.js +7 -5
- package/lib/assess/propagators/querystring/stringify.js +25 -24
- package/lib/assess/propagators/querystring/unescape.js +20 -18
- package/lib/assess/propagators/sequelize/sql-string-escape.js +1 -1
- package/lib/assess/propagators/sequelize/sql-string-format-named-parameters.js +1 -1
- package/lib/assess/propagators/sequelize/sql-string-format.js +3 -3
- package/lib/assess/propagators/sequelize/utils.js +2 -2
- package/lib/assess/propagators/string-prototype-replace.js +30 -28
- package/lib/assess/propagators/string-prototype-split.js +36 -36
- package/lib/assess/propagators/string-prototype-trim.js +15 -17
- package/lib/assess/propagators/string.js +12 -16
- package/lib/assess/propagators/template-escape.js +87 -0
- package/lib/assess/propagators/templates.js +10 -11
- package/lib/assess/propagators/url/url-prototype-parse.js +5 -6
- package/lib/assess/propagators/url/url-url.js +51 -43
- package/lib/assess/propagators/util/format.js +1 -1
- package/lib/assess/propagators/v8/init-hooks.js +3 -3
- package/lib/assess/propagators/validator/init-hooks.js +22 -22
- package/lib/assess/sinks/common.js +10 -5
- package/lib/assess/sinks/dustjs-linkedin-xss.js +131 -0
- package/lib/assess/sinks/libxmljs-xxe.js +1 -1
- package/lib/assess/sinks/mongodb.js +2 -1
- package/lib/assess/sinks/ssrf-url.js +1 -1
- package/lib/constants.js +4 -1
- package/lib/core/arch-components/dynamodb.js +1 -2
- package/lib/core/arch-components/dynamodbv3.js +44 -0
- package/lib/core/arch-components/index.js +1 -0
- package/lib/core/arch-components/rethinkdb.js +53 -0
- package/lib/core/config/options.js +3 -2
- package/lib/core/rewrite/injections.js +8 -0
- package/lib/core/stacktrace.js +2 -1
- package/lib/feature-set.js +1 -1
- package/lib/hooks/frameworks/base.js +8 -2
- package/lib/hooks/frameworks/http.js +23 -16
- package/lib/hooks/frameworks/http2.js +73 -0
- package/lib/hooks/frameworks/index.js +8 -3
- package/lib/hooks/http.js +112 -128
- package/lib/hooks/object-to-primitive.js +6 -7
- package/lib/hooks/patcher.js +75 -44
- package/lib/hooks/require.js +16 -22
- package/lib/instrumentation.js +0 -3
- package/lib/protect/rules/nosqli/nosql-injection-rule.js +228 -0
- package/lib/protect/rules/rule-factory.js +2 -2
- package/lib/protect/service.js +23 -11
- package/lib/protect/sinks/mongodb.js +56 -55
- package/lib/reporter/translations/to-protobuf/dtm/index.js +1 -1
- package/lib/reporter/translations/to-protobuf/dtm/ip-denylist-details.js +1 -1
- package/lib/reporter/translations/to-protobuf/dtm/rasp-rule-sample.js +1 -1
- package/lib/reporter/translations/to-protobuf/settings/defend-features.js +8 -6
- package/lib/reporter/translations/to-protobuf/settings/exclusions.js +5 -4
- package/lib/tracker.js +13 -65
- package/lib/util/some.js +27 -0
- package/lib/util/source-map.js +1 -1
- package/package.json +15 -16
- package/lib/hooks/frameworks/https.js +0 -42
- package/lib/protect/rules/nosqli/no-sql-injection-rule.js +0 -109
- package/node_modules/bindings/LICENSE.md +0 -22
- package/node_modules/bindings/README.md +0 -98
- package/node_modules/bindings/bindings.js +0 -221
- package/node_modules/bindings/package.json +0 -32
- package/node_modules/file-uri-to-path/.npmignore +0 -1
- package/node_modules/file-uri-to-path/.travis.yml +0 -30
- package/node_modules/file-uri-to-path/History.md +0 -21
- package/node_modules/file-uri-to-path/LICENSE +0 -20
- package/node_modules/file-uri-to-path/README.md +0 -74
- package/node_modules/file-uri-to-path/index.d.ts +0 -2
- package/node_modules/file-uri-to-path/index.js +0 -66
- package/node_modules/file-uri-to-path/package.json +0 -36
- package/node_modules/file-uri-to-path/test/test.js +0 -24
- package/node_modules/file-uri-to-path/test/tests.json +0 -13
- package/node_modules/glossy/LICENSE +0 -19
- package/node_modules/glossy/README.md +0 -129
- package/node_modules/glossy/index.js +0 -12
- package/node_modules/glossy/lib/glossy/parse.js +0 -520
- package/node_modules/glossy/lib/glossy/produce.js +0 -459
- package/node_modules/glossy/package.json +0 -47
- package/node_modules/glossy/test/decide.js +0 -7
- package/node_modules/glossy/test/decode_pri.js +0 -24
- package/node_modules/glossy/test/parse_3164.js +0 -104
- package/node_modules/glossy/test/parse_5424.js +0 -106
- package/node_modules/glossy/test/parse_5848.js +0 -40
- package/node_modules/glossy/test/parse_8601.js +0 -14
- package/node_modules/glossy/test/parse_rfc3339.js +0 -9
- package/node_modules/glossy/test/produce.js +0 -162
- package/node_modules/glossy/test/runner.js +0 -40
- package/node_modules/glossy/test/structure_data.js +0 -24
- package/node_modules/nan/CHANGELOG.md +0 -537
- package/node_modules/nan/LICENSE.md +0 -13
- package/node_modules/nan/README.md +0 -455
- package/node_modules/nan/doc/asyncworker.md +0 -146
- package/node_modules/nan/doc/buffers.md +0 -54
- package/node_modules/nan/doc/callback.md +0 -76
- package/node_modules/nan/doc/converters.md +0 -41
- package/node_modules/nan/doc/errors.md +0 -226
- package/node_modules/nan/doc/json.md +0 -62
- package/node_modules/nan/doc/maybe_types.md +0 -583
- package/node_modules/nan/doc/methods.md +0 -664
- package/node_modules/nan/doc/new.md +0 -147
- package/node_modules/nan/doc/node_misc.md +0 -123
- package/node_modules/nan/doc/object_wrappers.md +0 -263
- package/node_modules/nan/doc/persistent.md +0 -296
- package/node_modules/nan/doc/scopes.md +0 -73
- package/node_modules/nan/doc/script.md +0 -38
- package/node_modules/nan/doc/string_bytes.md +0 -62
- package/node_modules/nan/doc/v8_internals.md +0 -199
- package/node_modules/nan/doc/v8_misc.md +0 -85
- package/node_modules/nan/include_dirs.js +0 -1
- package/node_modules/nan/nan.h +0 -2898
- package/node_modules/nan/nan_callbacks.h +0 -88
- package/node_modules/nan/nan_callbacks_12_inl.h +0 -514
- package/node_modules/nan/nan_callbacks_pre_12_inl.h +0 -520
- package/node_modules/nan/nan_converters.h +0 -72
- package/node_modules/nan/nan_converters_43_inl.h +0 -68
- package/node_modules/nan/nan_converters_pre_43_inl.h +0 -42
- package/node_modules/nan/nan_define_own_property_helper.h +0 -29
- package/node_modules/nan/nan_implementation_12_inl.h +0 -430
- package/node_modules/nan/nan_implementation_pre_12_inl.h +0 -263
- package/node_modules/nan/nan_json.h +0 -166
- package/node_modules/nan/nan_maybe_43_inl.h +0 -356
- package/node_modules/nan/nan_maybe_pre_43_inl.h +0 -268
- package/node_modules/nan/nan_new.h +0 -340
- package/node_modules/nan/nan_object_wrap.h +0 -156
- package/node_modules/nan/nan_persistent_12_inl.h +0 -132
- package/node_modules/nan/nan_persistent_pre_12_inl.h +0 -242
- package/node_modules/nan/nan_private.h +0 -73
- package/node_modules/nan/nan_string_bytes.h +0 -305
- package/node_modules/nan/nan_typedarray_contents.h +0 -96
- package/node_modules/nan/nan_weak.h +0 -437
- package/node_modules/nan/package.json +0 -41
- package/node_modules/nan/tools/1to2.js +0 -412
- package/node_modules/nan/tools/README.md +0 -14
- package/node_modules/nan/tools/package.json +0 -19
- package/node_modules/unix-dgram/LICENSE +0 -13
- package/node_modules/unix-dgram/README.md +0 -107
- package/node_modules/unix-dgram/binding.gyp +0 -20
- package/node_modules/unix-dgram/build/Makefile +0 -324
- package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram/src/unix_dgram.o.d +0 -58
- package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram.node.d +0 -1
- package/node_modules/unix-dgram/build/Release/.deps/Release/unix_dgram.node.d +0 -1
- package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram/src/unix_dgram.o +0 -0
- package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram.node +0 -0
- package/node_modules/unix-dgram/build/Release/unix_dgram.node +0 -0
- package/node_modules/unix-dgram/build/binding.Makefile +0 -6
- package/node_modules/unix-dgram/build/config.gypi +0 -213
- package/node_modules/unix-dgram/build/unix_dgram.target.mk +0 -159
- package/node_modules/unix-dgram/lib/unix_dgram.js +0 -168
- package/node_modules/unix-dgram/package.json +0 -36
- package/node_modules/unix-dgram/src/unix_dgram.cc +0 -404
- package/node_modules/unix-dgram/src/win_dummy.cc +0 -7
- package/node_modules/unix-dgram/test/test-connect-callback.js +0 -68
- package/node_modules/unix-dgram/test/test-connect.js +0 -53
- package/node_modules/unix-dgram/test/test-dgram-unix.js +0 -58
- package/node_modules/unix-dgram/test/test-send-error.js +0 -26
- package/node_modules/winston-syslog/.eslintrc +0 -7
- package/node_modules/winston-syslog/.travis.yml +0 -14
- package/node_modules/winston-syslog/CHANGELOG.md +0 -9
- package/node_modules/winston-syslog/LICENSE +0 -20
- package/node_modules/winston-syslog/README.md +0 -135
- package/node_modules/winston-syslog/lib/utils.js +0 -26
- package/node_modules/winston-syslog/lib/winston-syslog.js +0 -385
- package/node_modules/winston-syslog/package.json +0 -56
- package/node_modules/winston-syslog/test/format-test.js +0 -122
- package/node_modules/winston-syslog/test/syslog-test.js +0 -95
- package/node_modules/winston-syslog/test/unix-connect-test.js +0 -133
|
@@ -71,6 +71,9 @@ function setHostnamePortTags(urlObj, stack, args, sourceEvent) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const hostData = tracker.getData(urlObj._contrast_host);
|
|
74
|
+
if (!hostData) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
74
77
|
const hostnameTags = tagRangeUtil.trim(hostData.tagRanges, 0, splitIndex - 1);
|
|
75
78
|
const portTags = tagRangeUtil.trim(
|
|
76
79
|
hostData.tagRanges,
|
|
@@ -81,21 +84,25 @@ function setHostnamePortTags(urlObj, stack, args, sourceEvent) {
|
|
|
81
84
|
|
|
82
85
|
if (hostnameTags.length > 0) {
|
|
83
86
|
const hostnameTracked = tracker.track(hostname);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
if (hostnameTracked) {
|
|
88
|
+
hostnameTracked.props.tagRanges = hostnameTags;
|
|
89
|
+
urlObj._contrast_hostname = hostnameTracked.str;
|
|
90
|
+
event = createEvent('url.URL', stack, hostnameTags, hostname, args, urlObj);
|
|
91
|
+
event.parents.push(sourceEvent);
|
|
92
|
+
event.tagRanges = hostnameTags;
|
|
93
|
+
hostnameTracked.props.event = event;
|
|
94
|
+
}
|
|
90
95
|
}
|
|
91
96
|
if (portTags.length > 0) {
|
|
92
97
|
const portTracked = tracker.track(port);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
if (portTracked) {
|
|
99
|
+
portTracked.props.tagRanges = portTags;
|
|
100
|
+
urlObj._contrast_port = portTracked.str;
|
|
101
|
+
event = createEvent('url.URL', stack, portTags, port, args, urlObj);
|
|
102
|
+
event.parents.push(sourceEvent);
|
|
103
|
+
event.tagRanges = portTags;
|
|
104
|
+
portTracked.props.event = event;
|
|
105
|
+
}
|
|
99
106
|
}
|
|
100
107
|
}
|
|
101
108
|
|
|
@@ -136,26 +143,28 @@ function joinProperties(urlObj, sourceProps, separators) {
|
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
// copy tag ranges
|
|
139
|
-
const result = tracker.track(value);
|
|
140
146
|
let valIdx = 0;
|
|
141
147
|
sepIdx = 0;
|
|
142
148
|
let tags = [];
|
|
143
149
|
|
|
144
150
|
for (const prop of sourceProps) {
|
|
145
|
-
|
|
151
|
+
const trackedPropData = tracker.getData(urlObj[`_contrast_${prop}`]);
|
|
152
|
+
if (trackedPropData) {
|
|
146
153
|
tags = tagRangeUtil.addAll(
|
|
147
154
|
tags,
|
|
148
155
|
offsetTagRanges(
|
|
149
|
-
|
|
156
|
+
trackedPropData.tagRanges,
|
|
150
157
|
valIdx
|
|
151
158
|
)
|
|
152
159
|
);
|
|
153
160
|
}
|
|
154
161
|
valIdx += urlObj[prop].length + separators[sepIdx++].length;
|
|
155
162
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
const tracked = tracker.track(value);
|
|
164
|
+
if (tracked) {
|
|
165
|
+
tracked.props.tagRanges = tags;
|
|
166
|
+
return tracked.str;
|
|
167
|
+
}
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
/**
|
|
@@ -172,7 +181,8 @@ function setOriginTags(urlObj, stack, args, sourceEvent) {
|
|
|
172
181
|
//
|
|
173
182
|
|
|
174
183
|
const trackedOrigin = joinProperties(urlObj, SET_ORIGIN_TAGS, ['//', '']);
|
|
175
|
-
|
|
184
|
+
const trackedOriginData = tracker.getData(trackedOrigin);
|
|
185
|
+
if (!trackedOriginData || trackedOriginData.tagRanges.length === 0) {
|
|
176
186
|
return;
|
|
177
187
|
}
|
|
178
188
|
urlObj._contrast_origin = trackedOrigin;
|
|
@@ -180,14 +190,14 @@ function setOriginTags(urlObj, stack, args, sourceEvent) {
|
|
|
180
190
|
const event = createEvent(
|
|
181
191
|
'url.URL',
|
|
182
192
|
stack,
|
|
183
|
-
|
|
193
|
+
trackedOriginData.tagRanges,
|
|
184
194
|
trackedOrigin,
|
|
185
195
|
args,
|
|
186
196
|
urlObj
|
|
187
197
|
);
|
|
188
198
|
event.parents.push(sourceEvent);
|
|
189
|
-
event.tagRanges =
|
|
190
|
-
|
|
199
|
+
event.tagRanges = trackedOriginData.tagRanges;
|
|
200
|
+
trackedOriginData.event = event;
|
|
191
201
|
}
|
|
192
202
|
|
|
193
203
|
/**
|
|
@@ -221,7 +231,7 @@ function setHrefTags(urlObj, stack, args, sourceEvent) {
|
|
|
221
231
|
|
|
222
232
|
const joinedHref = joinProperties(urlObj, properties, separators);
|
|
223
233
|
const joinedHrefData = tracker.getData(joinedHref);
|
|
224
|
-
if (joinedHrefData.tagRanges.length === 0) {
|
|
234
|
+
if (!joinedHrefData || joinedHrefData.tagRanges.length === 0) {
|
|
225
235
|
return;
|
|
226
236
|
}
|
|
227
237
|
urlObj._contrast_href = joinedHref;
|
|
@@ -235,7 +245,7 @@ function setHrefTags(urlObj, stack, args, sourceEvent) {
|
|
|
235
245
|
);
|
|
236
246
|
event.parents.push(sourceEvent);
|
|
237
247
|
event.tagRanges = joinedHrefData.tagRanges;
|
|
238
|
-
|
|
248
|
+
joinedHrefData.event = event;
|
|
239
249
|
}
|
|
240
250
|
|
|
241
251
|
/**
|
|
@@ -300,21 +310,22 @@ function copyTagsSingleSource(sourceTagRanges, sourceEvent, data) {
|
|
|
300
310
|
copied = true;
|
|
301
311
|
const trackedKey = `_contrast_${key}`;
|
|
302
312
|
const tracked = tracker.track(val);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
if (tracked) {
|
|
314
|
+
tracked.props.tagRanges = trimmed;
|
|
315
|
+
urlObj[trackedKey] = tracked.str;
|
|
316
|
+
|
|
317
|
+
// only create the stack once because stack creation is expensive
|
|
318
|
+
stack =
|
|
319
|
+
stack ||
|
|
320
|
+
stackFactory.createSnapshot({
|
|
321
|
+
constructorOpt: data.hooked
|
|
322
|
+
})();
|
|
323
|
+
|
|
324
|
+
event = createEvent('url.URL', stack, trimmed, val, args, urlObj);
|
|
325
|
+
event.parents.push(sourceEvent);
|
|
326
|
+
event.tagRanges = trimmed;
|
|
327
|
+
tracked.props.event = event;
|
|
328
|
+
}
|
|
318
329
|
}
|
|
319
330
|
|
|
320
331
|
if (!copied) {
|
|
@@ -351,10 +362,7 @@ function callUnwrapped(input) {
|
|
|
351
362
|
*/
|
|
352
363
|
function skipTracking(inputData, baseData) {
|
|
353
364
|
// if neither input or base are tracked we can just skip tracking
|
|
354
|
-
if (
|
|
355
|
-
(!inputData.tracked && baseData && !baseData.tracked) ||
|
|
356
|
-
(!inputData.tracked && !baseData)
|
|
357
|
-
) {
|
|
365
|
+
if (!inputData && !baseData) {
|
|
358
366
|
return true;
|
|
359
367
|
}
|
|
360
368
|
return false;
|
|
@@ -266,7 +266,7 @@ const propagate = function propagate(util, data) {
|
|
|
266
266
|
};
|
|
267
267
|
|
|
268
268
|
const fmtStrMeta = tracker.getData(fmtStr);
|
|
269
|
-
if (fmtStrMeta
|
|
269
|
+
if (fmtStrMeta) {
|
|
270
270
|
resultMeta.fmtStrTagRanges = fmtStrMeta.tagRanges.map((tagRange) =>
|
|
271
271
|
tagRangeWithOriginals(
|
|
272
272
|
new TagRange(tagRange.start, tagRange.stop, tagRange.tag)
|
|
@@ -63,7 +63,7 @@ module.exports.handle = function handle() {
|
|
|
63
63
|
if (tracked) {
|
|
64
64
|
// it was behind a membrane
|
|
65
65
|
data.result[TRACKED] = tracked;
|
|
66
|
-
} else if (tracker.
|
|
66
|
+
} else if (tracker.getData(data.args[0])) {
|
|
67
67
|
// it was a tracked string
|
|
68
68
|
data.result[TRACKED] = data.args[0];
|
|
69
69
|
}
|
|
@@ -80,13 +80,13 @@ module.exports.handle = function handle() {
|
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const sTracking = tracker.
|
|
83
|
+
const sTracking = tracker.getData(tracked);
|
|
84
84
|
// if the argument was a tracked string then the result should
|
|
85
85
|
// have the same tags. i don't know that the length of a string
|
|
86
86
|
// can change as a result of deserialize(serialize()) but best
|
|
87
87
|
// to be safe.
|
|
88
88
|
if (sTracking) {
|
|
89
|
-
const resultTracking = tracker.
|
|
89
|
+
const resultTracking = tracker.track(data.result);
|
|
90
90
|
if (!resultTracking) {
|
|
91
91
|
// there's nothing to do if tracking failed on the result. it should
|
|
92
92
|
// only do so on a zero-length string, but node works in mysterious ways.
|
|
@@ -90,7 +90,7 @@ module.exports.handle = function() {
|
|
|
90
90
|
function post(data) {
|
|
91
91
|
if (data.result) {
|
|
92
92
|
const trackingData = tracker.getData(data.args[0]);
|
|
93
|
-
if (trackingData
|
|
93
|
+
if (trackingData) {
|
|
94
94
|
tagRangeUtil.addInPlace(
|
|
95
95
|
trackingData.tagRanges,
|
|
96
96
|
new TagRange(0, data.args[0].length - 1, validators[validator])
|
|
@@ -131,7 +131,7 @@ module.exports.handle = function() {
|
|
|
131
131
|
function post(data) {
|
|
132
132
|
if (data.result) {
|
|
133
133
|
const trackingData = tracker.getData(data.args[0]);
|
|
134
|
-
if (trackingData
|
|
134
|
+
if (trackingData) {
|
|
135
135
|
trackingData.tagRanges = [];
|
|
136
136
|
trackingData.tracked = false;
|
|
137
137
|
}
|
|
@@ -154,36 +154,36 @@ module.exports.handle = function() {
|
|
|
154
154
|
function post(data) {
|
|
155
155
|
// if not tracked then it can't be untrusted, so don't start
|
|
156
156
|
// tracking this string.
|
|
157
|
-
|
|
157
|
+
const inputData = tracker.getData(data.args[0]);
|
|
158
|
+
if (!inputData) return;
|
|
158
159
|
|
|
159
160
|
const tag = sanitizers[sanitizer];
|
|
160
|
-
// get existing tracker data
|
|
161
|
-
const inputData = tracker.getData(data.args[0]);
|
|
162
161
|
|
|
163
162
|
// are the input and output of the sanitizer the same?
|
|
164
163
|
if (data.args[0] !== data.result) {
|
|
165
164
|
let needsTag = true;
|
|
166
165
|
// the input and output strings are not the same. start tracking the output.
|
|
167
|
-
const
|
|
168
|
-
const resultData = tracker.getData(result);
|
|
166
|
+
const tracked = tracker.track(data.result);
|
|
169
167
|
// copy the input tags to the result, adjusting the range.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
168
|
+
if (tracked) {
|
|
169
|
+
const stop = data.result.length - 1;
|
|
170
|
+
for (let i = 0; i < inputData.tagRanges.length; i++) {
|
|
171
|
+
tracked.props.tagRanges[i] = new TagRange(
|
|
172
|
+
0,
|
|
173
|
+
stop,
|
|
174
|
+
inputData.tagRanges[i].tag
|
|
175
|
+
);
|
|
176
|
+
if (inputData.tagRanges[i].tag === tag) {
|
|
177
|
+
needsTag = false;
|
|
178
|
+
}
|
|
179
179
|
}
|
|
180
|
+
if (needsTag) {
|
|
181
|
+
tracked.props.tagRanges.push(
|
|
182
|
+
new TagRange(0, stop, sanitizers[sanitizer])
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
data.result = tracked.str;
|
|
180
186
|
}
|
|
181
|
-
if (needsTag) {
|
|
182
|
-
resultData.tagRanges.push(
|
|
183
|
-
new TagRange(0, stop, sanitizers[sanitizer])
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
data.result = result;
|
|
187
187
|
} else {
|
|
188
188
|
// the input and output strings are the same, so the output is already being
|
|
189
189
|
// tracked. if the tag is already present adjust the bounds otherwise add the
|
|
@@ -78,7 +78,9 @@ module.exports = (agent) => {
|
|
|
78
78
|
// get the tags, event from dataflow actions ONLY
|
|
79
79
|
if (sinkType === DATAFLOW) {
|
|
80
80
|
const contrastProps = tracker.getData(input);
|
|
81
|
-
(
|
|
81
|
+
if (contrastProps) {
|
|
82
|
+
({ tagRanges, event } = contrastProps);
|
|
83
|
+
}
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
const sink = new SinkEvent({
|
|
@@ -189,7 +191,7 @@ module.exports = (agent) => {
|
|
|
189
191
|
) {
|
|
190
192
|
const trackData = tracker.getData(value);
|
|
191
193
|
|
|
192
|
-
if (!trackData
|
|
194
|
+
if (!trackData) {
|
|
193
195
|
return;
|
|
194
196
|
}
|
|
195
197
|
|
|
@@ -415,9 +417,12 @@ module.exports = (agent) => {
|
|
|
415
417
|
: common.nonDataflowVulnerableCheck({ sink });
|
|
416
418
|
|
|
417
419
|
const checkedArgs = isVulnCheck(stack, result, args);
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
420
|
+
if (Array.isArray(checkedArgs) && checkedArgs.length > 0) {
|
|
421
|
+
const mode = conditions ? conditions.mode : 'and';
|
|
422
|
+
return reduceConditions(checkedArgs, mode);
|
|
423
|
+
} else {
|
|
424
|
+
return checkedArgs;
|
|
425
|
+
}
|
|
421
426
|
};
|
|
422
427
|
|
|
423
428
|
/**
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 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 patcher = require('../../hooks/patcher');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const moduleHook = require('../../hooks/require');
|
|
20
|
+
const { CallContext, Signature } = require('../models');
|
|
21
|
+
const {
|
|
22
|
+
RULES: { REFLECTED_XSS }
|
|
23
|
+
} = require('../../constants');
|
|
24
|
+
|
|
25
|
+
const signature = new Signature({
|
|
26
|
+
moduleName: 'http.ClientResponse',
|
|
27
|
+
methodName: 'write',
|
|
28
|
+
isModule: true
|
|
29
|
+
});
|
|
30
|
+
const moduleName = 'dustjs-linkedin';
|
|
31
|
+
|
|
32
|
+
class Handler {
|
|
33
|
+
constructor({ report, isVulnerable, requiredTags, xss: { disallowedTags } }) {
|
|
34
|
+
this._isVulnerable = isVulnerable;
|
|
35
|
+
this.report = report;
|
|
36
|
+
this.requiredTags = requiredTags;
|
|
37
|
+
this.disallowedTags = disallowedTags;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
isVulnerable(input) {
|
|
41
|
+
const { requiredTags, disallowedTags } = this;
|
|
42
|
+
const ret = this._isVulnerable({
|
|
43
|
+
input,
|
|
44
|
+
ruleId: REFLECTED_XSS,
|
|
45
|
+
disallowedTags,
|
|
46
|
+
requiredTags
|
|
47
|
+
});
|
|
48
|
+
return ret;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
handle() {
|
|
52
|
+
moduleHook.resolve({ name: moduleName }, (dust) =>
|
|
53
|
+
this.handleRequire(dust)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getType(obj) {
|
|
58
|
+
return obj && obj.constructor && obj.constructor.name;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isResponseType(typeName) {
|
|
62
|
+
return typeName === 'ServerResponse';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
patchDust(dust) {
|
|
66
|
+
const self = this;
|
|
67
|
+
patcher.patch(dust, 'stream', {
|
|
68
|
+
name: moduleName,
|
|
69
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
70
|
+
alwaysRun: true,
|
|
71
|
+
post(data) {
|
|
72
|
+
self.patchStream(data.result);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Patch the pipe method and check wether the stream is targeting a
|
|
79
|
+
* response instance. If so, add the instance to the set of streams
|
|
80
|
+
* we should follow.
|
|
81
|
+
*/
|
|
82
|
+
patchStream(streamInstance) {
|
|
83
|
+
const self = this;
|
|
84
|
+
patcher.patch(streamInstance, 'pipe', {
|
|
85
|
+
name: 'dust.Stream.prototype',
|
|
86
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
87
|
+
alwaysRun: true,
|
|
88
|
+
pre({ args: [maybeRes] }) {
|
|
89
|
+
self.patchStreamTarget(maybeRes);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
patchStreamTarget(target) {
|
|
95
|
+
const self = this;
|
|
96
|
+
const typeName = self.getType(target);
|
|
97
|
+
|
|
98
|
+
if (self.isResponseType(typeName)) {
|
|
99
|
+
patcher.patch(target, 'write', {
|
|
100
|
+
name: 'dust.pipeTarget',
|
|
101
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
102
|
+
alwaysRun: true,
|
|
103
|
+
post({ args: [str], hooked }) {
|
|
104
|
+
if (self.isVulnerable(str)) {
|
|
105
|
+
self.report({
|
|
106
|
+
ruleId: REFLECTED_XSS,
|
|
107
|
+
signature,
|
|
108
|
+
input: str,
|
|
109
|
+
ctxt: new CallContext({
|
|
110
|
+
obj: typeName,
|
|
111
|
+
args: [str],
|
|
112
|
+
result: str,
|
|
113
|
+
stackOpts: {
|
|
114
|
+
constructorOpt: hooked
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
handleRequire(dust) {
|
|
125
|
+
this.patchDust(dust);
|
|
126
|
+
return dust;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = ({ common }) => new Handler(common);
|
|
131
|
+
module.exports.Handler = Handler;
|
package/lib/constants.js
CHANGED
|
@@ -108,8 +108,11 @@ const RULES = {
|
|
|
108
108
|
'cmd-injection-semantic-chained-commands',
|
|
109
109
|
CMD_INJECTION_SEMANTIC_DANGEROUS_PATHS:
|
|
110
110
|
'cmd-injection-semantic-dangerous-paths',
|
|
111
|
-
IP_DENYLIST: 'ip-
|
|
111
|
+
IP_DENYLIST: 'ip-denylist',
|
|
112
112
|
METHOD_TAMPERING: 'method-tampering',
|
|
113
|
+
// The following is not a known rule in TS and is only used by SR when
|
|
114
|
+
// reporting certain analysis results. We convert to nosqli before reporting
|
|
115
|
+
NOSQL_EXPANSION: 'nosql-expansion',
|
|
113
116
|
NOSQL_INJECTION: 'nosql-injection',
|
|
114
117
|
PATH_TRAVERSAL: 'path-traversal',
|
|
115
118
|
REFLECTED_XSS: 'reflected-xss',
|
|
@@ -18,7 +18,6 @@ const agentEmitter = require('../../agent-emitter');
|
|
|
18
18
|
const { PATCH_TYPES } = require('../../constants');
|
|
19
19
|
const ModuleHook = require('../../hooks/require');
|
|
20
20
|
const patcher = require('../../hooks/patcher');
|
|
21
|
-
const _ = require('lodash');
|
|
22
21
|
|
|
23
22
|
ModuleHook.resolve({ name: 'aws-sdk' }, (AWS) => {
|
|
24
23
|
patcher.patch(AWS.DynamoDB.prototype, 'makeRequest', {
|
|
@@ -27,7 +26,7 @@ ModuleHook.resolve({ name: 'aws-sdk' }, (AWS) => {
|
|
|
27
26
|
alwaysRun: true,
|
|
28
27
|
post(ctx) {
|
|
29
28
|
try {
|
|
30
|
-
const endpoint =
|
|
29
|
+
const { endpoint } = this;
|
|
31
30
|
agentEmitter.emit('architectureComponent', {
|
|
32
31
|
vendor: 'DynamoDB',
|
|
33
32
|
url: new URL(`${endpoint.protocol}//${endpoint.hostname}`).toString(),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 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
|
+
const logger = require('../logger')('contrast:arch-component');
|
|
17
|
+
const agentEmitter = require('../../agent-emitter');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const ModuleHook = require('../../hooks/require');
|
|
20
|
+
const patcher = require('../../hooks/patcher');
|
|
21
|
+
|
|
22
|
+
function emitArchitectureComponent(endpoint) {
|
|
23
|
+
agentEmitter.emit('architectureComponent', {
|
|
24
|
+
vendor: 'DynamoDB',
|
|
25
|
+
url: new URL(`${endpoint.protocol}//${endpoint.hostname}`).toString(),
|
|
26
|
+
remoteHost: '',
|
|
27
|
+
remotePort: endpoint.port
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ModuleHook.resolve({ name: '@aws-sdk/client-dynamodb' }, (AWS) => {
|
|
32
|
+
patcher.patch(AWS.DynamoDBClient.prototype, 'send', {
|
|
33
|
+
name: 'DynamoDBv3.arch_component',
|
|
34
|
+
patchType: PATCH_TYPES.ARCH_COMPONENT,
|
|
35
|
+
alwaysRun: true,
|
|
36
|
+
post(ctx) {
|
|
37
|
+
try {
|
|
38
|
+
this.config.endpoint().then(emitArchitectureComponent);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
logger.warn('unable to report DynamoDB architecture component\n', err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 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 agentEmitter = require('../../agent-emitter');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const ModuleHook = require('../../hooks/require');
|
|
20
|
+
const patcher = require('../../hooks/patcher');
|
|
21
|
+
const logger = require('../logger')('contrast:arch-component');
|
|
22
|
+
|
|
23
|
+
ModuleHook.resolve({ name: 'rethinkdb' }, (rethinkdb) => {
|
|
24
|
+
patcher.patch(rethinkdb, 'connect', {
|
|
25
|
+
name: 'rethinkdb.arch_component',
|
|
26
|
+
patchType: PATCH_TYPES.ARCH_COMPONENT,
|
|
27
|
+
alwaysRun: true,
|
|
28
|
+
post(ctx) {
|
|
29
|
+
ctx.result
|
|
30
|
+
.then((res) => {
|
|
31
|
+
if (res.open) {
|
|
32
|
+
const url =
|
|
33
|
+
res.host == 'localhost'
|
|
34
|
+
? 'http://localhost'
|
|
35
|
+
: new URL(res.host).toString();
|
|
36
|
+
agentEmitter.emit('architectureComponent', {
|
|
37
|
+
vendor: 'RethinkDB',
|
|
38
|
+
url,
|
|
39
|
+
remotePort: res.port
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
logger.warn('unable to open RethinkDB connection');
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.catch((err) => {
|
|
46
|
+
logger.warn(
|
|
47
|
+
'unable to report RethinkDB architecture component\n%o',
|
|
48
|
+
err
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -284,7 +284,7 @@ const agent = [
|
|
|
284
284
|
{
|
|
285
285
|
name: 'agent.node.array_request_sampling.enable',
|
|
286
286
|
arg: '[false]',
|
|
287
|
-
default:
|
|
287
|
+
default: false,
|
|
288
288
|
fn: castBoolean,
|
|
289
289
|
desc: 'enable sampling of array members for dataflow'
|
|
290
290
|
},
|
|
@@ -483,7 +483,8 @@ const agent = [
|
|
|
483
483
|
arg: '<limit>',
|
|
484
484
|
default: 10,
|
|
485
485
|
fn: parseNum,
|
|
486
|
-
desc:
|
|
486
|
+
desc:
|
|
487
|
+
'set limit for stack trace size (larger limits will improve accuracy but increase memory usage)'
|
|
487
488
|
},
|
|
488
489
|
{
|
|
489
490
|
name: 'agent.polling.app_activity_ms',
|
|
@@ -131,6 +131,14 @@ const injections = {
|
|
|
131
131
|
name: 'String',
|
|
132
132
|
patchType: PATCH_TYPES.INJECTION
|
|
133
133
|
})
|
|
134
|
+
),
|
|
135
|
+
Number: new Injection(
|
|
136
|
+
'Number',
|
|
137
|
+
'ContrastNumber',
|
|
138
|
+
patcher.patch(global.Number, {
|
|
139
|
+
name: 'Number',
|
|
140
|
+
patchType: PATCH_TYPES.INJECTION
|
|
141
|
+
})
|
|
134
142
|
)
|
|
135
143
|
};
|
|
136
144
|
|
package/lib/core/stacktrace.js
CHANGED
|
@@ -15,11 +15,12 @@ Copyright: 2021 Contrast Security, Inc
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const semver = require('semver');
|
|
18
|
+
const agent = require('../agent');
|
|
18
19
|
const process = require('process');
|
|
19
20
|
const sourceMap = require('../util/source-map');
|
|
20
21
|
const _isAgentPath = require('../util/is-agent-path');
|
|
21
22
|
|
|
22
|
-
const STACK_TRACE_LIMIT =
|
|
23
|
+
const STACK_TRACE_LIMIT = agent.config.agent.stack_trace_limit;
|
|
23
24
|
const EVAL_ORIGIN_REGEX = /\((.*?):(\d+):\d+\)/;
|
|
24
25
|
const EVENTS_FILE = semver.gte(process.version, '16.0.0')
|
|
25
26
|
? 'node:events'
|