dd-trace 4.41.0 → 4.43.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-3rdparty.csv +1 -2
- package/ext/exporters.d.ts +1 -1
- package/index.d.ts +105 -37
- package/init.js +40 -1
- package/initialize.mjs +8 -5
- package/package.json +29 -29
- package/packages/datadog-core/src/storage/index.js +1 -10
- package/packages/datadog-esbuild/index.js +5 -1
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
- package/packages/datadog-instrumentations/src/child_process.js +2 -2
- package/packages/datadog-instrumentations/src/cucumber.js +76 -34
- package/packages/datadog-instrumentations/src/fs.js +1 -1
- package/packages/datadog-instrumentations/src/hapi.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hook.js +8 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +4 -3
- package/packages/datadog-instrumentations/src/helpers/register.js +56 -5
- package/packages/datadog-instrumentations/src/http/client.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +17 -2
- package/packages/datadog-instrumentations/src/kafkajs.js +1 -1
- package/packages/datadog-instrumentations/src/ldapjs.js +2 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +12 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +58 -14
- package/packages/datadog-instrumentations/src/mocha/worker.js +1 -0
- package/packages/datadog-instrumentations/src/mquery.js +2 -2
- package/packages/datadog-instrumentations/src/next.js +1 -1
- package/packages/datadog-instrumentations/src/pg.js +2 -2
- package/packages/datadog-instrumentations/src/playwright.js +47 -33
- package/packages/datadog-instrumentations/src/restify.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +349 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +8 -1
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +23 -5
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
- package/packages/datadog-plugin-child_process/src/index.js +1 -1
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -4
- package/packages/datadog-plugin-cucumber/src/index.js +24 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +79 -42
- package/packages/datadog-plugin-cypress/src/plugin.js +4 -3
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +7 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +25 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/index.js +57 -35
- package/packages/datadog-plugin-openai/src/token-estimator.js +20 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -1
- package/packages/datadog-plugin-sharedb/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +167 -0
- package/packages/dd-trace/src/analytics_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +2 -19
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +3 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -0
- package/packages/dd-trace/src/appsec/index.js +4 -4
- package/packages/dd-trace/src/appsec/passport.js +1 -1
- package/packages/dd-trace/src/appsec/rasp.js +32 -5
- package/packages/dd-trace/src/appsec/recommended.json +208 -3
- package/packages/dd-trace/src/appsec/reporter.js +60 -20
- package/packages/dd-trace/src/appsec/sdk/track_event.js +3 -0
- package/packages/dd-trace/src/appsec/stack_trace.js +90 -0
- package/packages/dd-trace/src/appsec/standalone.js +130 -0
- package/packages/dd-trace/src/appsec/telemetry.js +33 -1
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +3 -3
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/config.js +136 -63
- package/packages/dd-trace/src/constants.js +3 -1
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- package/packages/dd-trace/src/exporters/agent/index.js +2 -2
- package/packages/dd-trace/src/format.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentelemetry/tracer.js +6 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -0
- package/packages/dd-trace/src/opentracing/span.js +4 -1
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +7 -0
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +5 -1
- package/packages/dd-trace/src/priority_sampler.js +2 -5
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/proxy.js +3 -1
- package/packages/dd-trace/src/rate_limiter.js +2 -2
- package/packages/dd-trace/src/span_stats.js +4 -3
- package/packages/dd-trace/src/telemetry/init-telemetry.js +75 -0
- package/packages/dd-trace/src/tracer.js +2 -2
- package/packages/dd-trace/src/util.js +6 -1
- package/packages/datadog-core/src/storage/async_hooks.js +0 -49
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
2
|
+
const { storage } = require('../../datadog-core')
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
TEST_STATUS,
|
|
6
|
+
finishAllTraceSpans,
|
|
7
|
+
getTestSuitePath,
|
|
8
|
+
getTestSuiteCommonTags,
|
|
9
|
+
TEST_SOURCE_FILE,
|
|
10
|
+
TEST_IS_RETRY
|
|
11
|
+
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
|
+
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
13
|
+
|
|
14
|
+
// Milliseconds that we subtract from the error test duration
|
|
15
|
+
// so that they do not overlap with the following test
|
|
16
|
+
// This is because there's some loss of resolution.
|
|
17
|
+
const MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION = 5
|
|
18
|
+
|
|
19
|
+
class VitestPlugin extends CiPlugin {
|
|
20
|
+
static get id () {
|
|
21
|
+
return 'vitest'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor (...args) {
|
|
25
|
+
super(...args)
|
|
26
|
+
|
|
27
|
+
this.taskToFinishTime = new WeakMap()
|
|
28
|
+
|
|
29
|
+
this.addSub('ci:vitest:test:start', ({ testName, testSuiteAbsolutePath, isRetry }) => {
|
|
30
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
31
|
+
const store = storage.getStore()
|
|
32
|
+
|
|
33
|
+
const extraTags = {
|
|
34
|
+
[TEST_SOURCE_FILE]: testSuite
|
|
35
|
+
}
|
|
36
|
+
if (isRetry) {
|
|
37
|
+
extraTags[TEST_IS_RETRY] = 'true'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const span = this.startTestSpan(
|
|
41
|
+
testName,
|
|
42
|
+
testSuite,
|
|
43
|
+
this.testSuiteSpan,
|
|
44
|
+
extraTags
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
this.enter(span, store)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
this.addSub('ci:vitest:test:finish-time', ({ status, task }) => {
|
|
51
|
+
const store = storage.getStore()
|
|
52
|
+
const span = store?.span
|
|
53
|
+
|
|
54
|
+
// we store the finish time to finish at a later hook
|
|
55
|
+
// this is because the test might fail at a `afterEach` hook
|
|
56
|
+
if (span) {
|
|
57
|
+
span.setTag(TEST_STATUS, status)
|
|
58
|
+
this.taskToFinishTime.set(task, span._getTime())
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
this.addSub('ci:vitest:test:pass', ({ task }) => {
|
|
63
|
+
const store = storage.getStore()
|
|
64
|
+
const span = store?.span
|
|
65
|
+
|
|
66
|
+
if (span) {
|
|
67
|
+
span.setTag(TEST_STATUS, 'pass')
|
|
68
|
+
span.finish(this.taskToFinishTime.get(task))
|
|
69
|
+
finishAllTraceSpans(span)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
this.addSub('ci:vitest:test:error', ({ duration, error }) => {
|
|
74
|
+
const store = storage.getStore()
|
|
75
|
+
const span = store?.span
|
|
76
|
+
|
|
77
|
+
if (span) {
|
|
78
|
+
span.setTag(TEST_STATUS, 'fail')
|
|
79
|
+
|
|
80
|
+
if (error) {
|
|
81
|
+
span.setTag('error', error)
|
|
82
|
+
}
|
|
83
|
+
if (duration) {
|
|
84
|
+
span.finish(span._startTime + duration - MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION) // milliseconds
|
|
85
|
+
} else {
|
|
86
|
+
span.finish() // retries will not have a duration
|
|
87
|
+
}
|
|
88
|
+
finishAllTraceSpans(span)
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
this.addSub('ci:vitest:test:skip', ({ testName, testSuiteAbsolutePath }) => {
|
|
93
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
94
|
+
this.startTestSpan(
|
|
95
|
+
testName,
|
|
96
|
+
testSuite,
|
|
97
|
+
this.testSuiteSpan,
|
|
98
|
+
{
|
|
99
|
+
[TEST_SOURCE_FILE]: testSuite,
|
|
100
|
+
[TEST_STATUS]: 'skip'
|
|
101
|
+
}
|
|
102
|
+
).finish()
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
this.addSub('ci:vitest:test-suite:start', (testSuiteAbsolutePath) => {
|
|
106
|
+
const testSessionSpanContext = this.tracer.extract('text_map', {
|
|
107
|
+
'x-datadog-trace-id': process.env.DD_CIVISIBILITY_TEST_SESSION_ID,
|
|
108
|
+
'x-datadog-parent-id': process.env.DD_CIVISIBILITY_TEST_MODULE_ID
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, this.repositoryRoot)
|
|
112
|
+
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
113
|
+
this.command,
|
|
114
|
+
this.frameworkVersion,
|
|
115
|
+
testSuite,
|
|
116
|
+
'vitest'
|
|
117
|
+
)
|
|
118
|
+
const testSuiteSpan = this.tracer.startSpan('vitest.test_suite', {
|
|
119
|
+
childOf: testSessionSpanContext,
|
|
120
|
+
tags: {
|
|
121
|
+
[COMPONENT]: this.constructor.id,
|
|
122
|
+
...this.testEnvironmentMetadata,
|
|
123
|
+
...testSuiteMetadata
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
const store = storage.getStore()
|
|
127
|
+
this.enter(testSuiteSpan, store)
|
|
128
|
+
this.testSuiteSpan = testSuiteSpan
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
this.addSub('ci:vitest:test-suite:finish', ({ status, onFinish }) => {
|
|
132
|
+
const store = storage.getStore()
|
|
133
|
+
const span = store?.span
|
|
134
|
+
if (span) {
|
|
135
|
+
span.setTag(TEST_STATUS, status)
|
|
136
|
+
span.finish()
|
|
137
|
+
finishAllTraceSpans(span)
|
|
138
|
+
}
|
|
139
|
+
// TODO: too frequent flush - find for method in worker to decrease frequency
|
|
140
|
+
this.tracer._exporter.flush(onFinish)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
this.addSub('ci:vitest:test-suite:error', ({ error }) => {
|
|
144
|
+
const store = storage.getStore()
|
|
145
|
+
const span = store?.span
|
|
146
|
+
if (span && error) {
|
|
147
|
+
span.setTag('error', error)
|
|
148
|
+
span.setTag(TEST_STATUS, 'fail')
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
this.addSub('ci:vitest:session:finish', ({ status, onFinish, error }) => {
|
|
153
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
154
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
155
|
+
if (error) {
|
|
156
|
+
this.testModuleSpan.setTag('error', error)
|
|
157
|
+
this.testSessionSpan.setTag('error', error)
|
|
158
|
+
}
|
|
159
|
+
this.testModuleSpan.finish()
|
|
160
|
+
this.testSessionSpan.finish()
|
|
161
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
162
|
+
this.tracer._exporter.flush(onFinish)
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = VitestPlugin
|
|
@@ -4,7 +4,7 @@ const { MEASURED } = require('../../../ext/tags')
|
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
sample (span, measured, measuredByDefault) {
|
|
7
|
-
if (typeof measured === 'object') {
|
|
7
|
+
if (measured !== null && typeof measured === 'object') {
|
|
8
8
|
this.sample(span, measured[span.context()._name], measuredByDefault)
|
|
9
9
|
} else if (measured !== undefined) {
|
|
10
10
|
span.setTag(MEASURED, !!measured)
|
|
@@ -13,7 +13,7 @@ const EXCLUDED_PATHS_FROM_STACK = getNodeModulesPaths('mongodb', 'mongoose', 'mq
|
|
|
13
13
|
const MONGODB_NOSQL_SECURE_MARK = getNextSecureMark()
|
|
14
14
|
|
|
15
15
|
function iterateObjectStrings (target, fn, levelKeys = [], depth = 20, visited = new Set()) {
|
|
16
|
-
if (target && typeof target === 'object') {
|
|
16
|
+
if (target !== null && typeof target === 'object') {
|
|
17
17
|
Object.keys(target).forEach((key) => {
|
|
18
18
|
const nextLevelKeys = [...levelKeys, key]
|
|
19
19
|
const val = target[key]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const process = require('process')
|
|
5
5
|
const { calculateDDBasePath } = require('../../util')
|
|
6
|
+
const { getCallSiteList } = require('../stack_trace')
|
|
6
7
|
const pathLine = {
|
|
7
8
|
getFirstNonDDPathAndLine,
|
|
8
9
|
getNodeModulesPaths,
|
|
@@ -24,24 +25,6 @@ const EXCLUDED_PATH_PREFIXES = [
|
|
|
24
25
|
'async_hooks'
|
|
25
26
|
]
|
|
26
27
|
|
|
27
|
-
function getCallSiteInfo () {
|
|
28
|
-
const previousPrepareStackTrace = Error.prepareStackTrace
|
|
29
|
-
const previousStackTraceLimit = Error.stackTraceLimit
|
|
30
|
-
let callsiteList
|
|
31
|
-
Error.stackTraceLimit = 100
|
|
32
|
-
try {
|
|
33
|
-
Error.prepareStackTrace = function (_, callsites) {
|
|
34
|
-
callsiteList = callsites
|
|
35
|
-
}
|
|
36
|
-
const e = new Error()
|
|
37
|
-
e.stack
|
|
38
|
-
} finally {
|
|
39
|
-
Error.prepareStackTrace = previousPrepareStackTrace
|
|
40
|
-
Error.stackTraceLimit = previousStackTraceLimit
|
|
41
|
-
}
|
|
42
|
-
return callsiteList
|
|
43
|
-
}
|
|
44
|
-
|
|
45
28
|
function getFirstNonDDPathAndLineFromCallsites (callsites, externallyExcludedPaths) {
|
|
46
29
|
if (callsites) {
|
|
47
30
|
for (let i = 0; i < callsites.length; i++) {
|
|
@@ -91,7 +74,7 @@ function isExcluded (callsite, externallyExcludedPaths) {
|
|
|
91
74
|
}
|
|
92
75
|
|
|
93
76
|
function getFirstNonDDPathAndLine (externallyExcludedPaths) {
|
|
94
|
-
return getFirstNonDDPathAndLineFromCallsites(
|
|
77
|
+
return getFirstNonDDPathAndLineFromCallsites(getCallSiteList(), externallyExcludedPaths)
|
|
95
78
|
}
|
|
96
79
|
|
|
97
80
|
function getNodeModulesPaths (...paths) {
|
|
@@ -45,7 +45,7 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
45
45
|
this.addSub(
|
|
46
46
|
{ channelName: 'apm:express:middleware:next', tag: HTTP_REQUEST_BODY },
|
|
47
47
|
({ req }) => {
|
|
48
|
-
if (req && req.body && typeof req.body === 'object') {
|
|
48
|
+
if (req && req.body !== null && typeof req.body === 'object') {
|
|
49
49
|
const iastContext = getIastContext(storage.getStore())
|
|
50
50
|
if (iastContext && iastContext.body !== req.body) {
|
|
51
51
|
this._taintTrackingHandler(HTTP_REQUEST_BODY, req, 'body', iastContext)
|
|
@@ -63,7 +63,7 @@ class TaintTrackingPlugin extends SourceIastPlugin {
|
|
|
63
63
|
this.addSub(
|
|
64
64
|
{ channelName: 'datadog:express:process_params:start', tag: HTTP_REQUEST_PATH_PARAM },
|
|
65
65
|
({ req }) => {
|
|
66
|
-
if (req && req.params && typeof req.params === 'object') {
|
|
66
|
+
if (req && req.params !== null && typeof req.params === 'object') {
|
|
67
67
|
this._taintTrackingHandler(HTTP_REQUEST_PATH_PARAM, req, 'params')
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -27,14 +27,14 @@ class KafkaConsumerIastPlugin extends SourceIastPlugin {
|
|
|
27
27
|
if (iastContext && message) {
|
|
28
28
|
const { key, value } = message
|
|
29
29
|
|
|
30
|
-
if (key && typeof key === 'object') {
|
|
30
|
+
if (key !== null && typeof key === 'object') {
|
|
31
31
|
shimmer.wrap(key, 'toString',
|
|
32
32
|
toString => this.getToStringWrap(toString, iastContext, KAFKA_MESSAGE_KEY))
|
|
33
33
|
|
|
34
34
|
newTaintedObject(iastContext, key, undefined, KAFKA_MESSAGE_KEY)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
if (value && typeof value === 'object') {
|
|
37
|
+
if (value !== null && typeof value === 'object') {
|
|
38
38
|
shimmer.wrap(value, 'toString',
|
|
39
39
|
toString => this.getToStringWrap(toString, iastContext, KAFKA_MESSAGE_VALUE))
|
|
40
40
|
|
|
@@ -43,6 +43,8 @@ class VulnerabilityFormatter {
|
|
|
43
43
|
const valueParts = []
|
|
44
44
|
let fromIndex = 0
|
|
45
45
|
|
|
46
|
+
if (evidence.value == null) return { valueParts }
|
|
47
|
+
|
|
46
48
|
if (typeof evidence.value === 'object' && evidence.rangesToApply) {
|
|
47
49
|
const { value, ranges } = stringifyWithRanges(evidence.value, evidence.rangesToApply)
|
|
48
50
|
evidence.value = value
|
|
@@ -69,7 +71,7 @@ class VulnerabilityFormatter {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
formatEvidence (type, evidence, sourcesIndexes, sources) {
|
|
72
|
-
if (
|
|
74
|
+
if (evidence.value === undefined) {
|
|
73
75
|
return undefined
|
|
74
76
|
}
|
|
75
77
|
|
|
@@ -4,6 +4,7 @@ const { MANUAL_KEEP } = require('../../../../../ext/tags')
|
|
|
4
4
|
const LRU = require('lru-cache')
|
|
5
5
|
const vulnerabilitiesFormatter = require('./vulnerabilities-formatter')
|
|
6
6
|
const { IAST_ENABLED_TAG_KEY, IAST_JSON_TAG_KEY } = require('./tags')
|
|
7
|
+
const standalone = require('../standalone')
|
|
7
8
|
|
|
8
9
|
const VULNERABILITIES_KEY = 'vulnerabilities'
|
|
9
10
|
const VULNERABILITY_HASHES_MAX_SIZE = 1000
|
|
@@ -57,6 +58,9 @@ function sendVulnerabilities (vulnerabilities, rootSpan) {
|
|
|
57
58
|
tags[IAST_JSON_TAG_KEY] = JSON.stringify(jsonToSend)
|
|
58
59
|
tags[MANUAL_KEEP] = 'true'
|
|
59
60
|
span.addTags(tags)
|
|
61
|
+
|
|
62
|
+
standalone.sample(span)
|
|
63
|
+
|
|
60
64
|
if (!rootSpan) span.finish()
|
|
61
65
|
}
|
|
62
66
|
}
|
|
@@ -40,7 +40,7 @@ function enable (_config) {
|
|
|
40
40
|
graphql.enable()
|
|
41
41
|
|
|
42
42
|
if (_config.appsec.rasp.enabled) {
|
|
43
|
-
rasp.enable()
|
|
43
|
+
rasp.enable(_config)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
setTemplates(_config)
|
|
@@ -121,16 +121,16 @@ function incomingHttpEndTranslator ({ req, res }) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// TODO: temporary express instrumentation, will use express plugin later
|
|
124
|
-
if (req.params && typeof req.params === 'object') {
|
|
124
|
+
if (req.params !== null && typeof req.params === 'object') {
|
|
125
125
|
persistent[addresses.HTTP_INCOMING_PARAMS] = req.params
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
// we need to keep this to support other cookie parsers
|
|
129
|
-
if (req.cookies && typeof req.cookies === 'object') {
|
|
129
|
+
if (req.cookies !== null && typeof req.cookies === 'object') {
|
|
130
130
|
persistent[addresses.HTTP_INCOMING_COOKIES] = req.cookies
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
if (req.query && typeof req.query === 'object') {
|
|
133
|
+
if (req.query !== null && typeof req.query === 'object') {
|
|
134
134
|
persistent[addresses.HTTP_INCOMING_QUERY] = req.query
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -13,7 +13,7 @@ const regexSdkEvent = new RegExp(SDK_USER_EVENT_PATTERN, 'i')
|
|
|
13
13
|
function isSdkCalled (tags) {
|
|
14
14
|
let called = false
|
|
15
15
|
|
|
16
|
-
if (tags && typeof tags === 'object') {
|
|
16
|
+
if (tags !== null && typeof tags === 'object') {
|
|
17
17
|
called = Object.entries(tags).some(([key, value]) => regexSdkEvent.test(key) && value === 'true')
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
|
+
const web = require('./../plugins/util/web')
|
|
4
5
|
const addresses = require('./addresses')
|
|
5
6
|
const { httpClientRequestStart } = require('./channels')
|
|
7
|
+
const { reportStackTrace } = require('./stack_trace')
|
|
6
8
|
const waf = require('./waf')
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
const RULE_TYPES = {
|
|
11
|
+
SSRF: 'ssrf'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let config
|
|
15
|
+
|
|
16
|
+
function enable (_config) {
|
|
17
|
+
config = _config
|
|
9
18
|
httpClientRequestStart.subscribe(analyzeSsrf)
|
|
10
19
|
}
|
|
11
20
|
|
|
@@ -24,12 +33,30 @@ function analyzeSsrf (ctx) {
|
|
|
24
33
|
[addresses.HTTP_OUTGOING_URL]: url
|
|
25
34
|
}
|
|
26
35
|
// TODO: Currently this is only monitoring, we should
|
|
27
|
-
// block the request if SSRF attempt
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
// block the request if SSRF attempt
|
|
37
|
+
const result = waf.run({ persistent }, req, RULE_TYPES.SSRF)
|
|
38
|
+
handleResult(result, req)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getGenerateStackTraceAction (actions) {
|
|
42
|
+
return actions?.generate_stack
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function handleResult (actions, req) {
|
|
46
|
+
const generateStackTraceAction = getGenerateStackTraceAction(actions)
|
|
47
|
+
if (generateStackTraceAction && config.appsec.stackTrace.enabled) {
|
|
48
|
+
const rootSpan = web.root(req)
|
|
49
|
+
reportStackTrace(
|
|
50
|
+
rootSpan,
|
|
51
|
+
generateStackTraceAction.stack_id,
|
|
52
|
+
config.appsec.stackTrace.maxDepth,
|
|
53
|
+
config.appsec.stackTrace.maxStackTraces
|
|
54
|
+
)
|
|
55
|
+
}
|
|
30
56
|
}
|
|
31
57
|
|
|
32
58
|
module.exports = {
|
|
33
59
|
enable,
|
|
34
|
-
disable
|
|
60
|
+
disable,
|
|
61
|
+
handleResult
|
|
35
62
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "2.2",
|
|
3
3
|
"metadata": {
|
|
4
|
-
"rules_version": "1.
|
|
4
|
+
"rules_version": "1.12.0"
|
|
5
5
|
},
|
|
6
6
|
"rules": [
|
|
7
7
|
{
|
|
@@ -1921,7 +1921,6 @@
|
|
|
1921
1921
|
"$ifs",
|
|
1922
1922
|
"$oldpwd",
|
|
1923
1923
|
"$ostype",
|
|
1924
|
-
"$path",
|
|
1925
1924
|
"$pwd",
|
|
1926
1925
|
"dev/fd/",
|
|
1927
1926
|
"dev/null",
|
|
@@ -5849,7 +5848,8 @@
|
|
|
5849
5848
|
"/website.php",
|
|
5850
5849
|
"/stats.php",
|
|
5851
5850
|
"/assets/plugins/mp3_id/mp3_id.php",
|
|
5852
|
-
"/siteminderagent/forms/smpwservices.fcc"
|
|
5851
|
+
"/siteminderagent/forms/smpwservices.fcc",
|
|
5852
|
+
"/eval-stdin.php"
|
|
5853
5853
|
]
|
|
5854
5854
|
}
|
|
5855
5855
|
}
|
|
@@ -6236,6 +6236,155 @@
|
|
|
6236
6236
|
],
|
|
6237
6237
|
"transformers": []
|
|
6238
6238
|
},
|
|
6239
|
+
{
|
|
6240
|
+
"id": "rasp-930-100",
|
|
6241
|
+
"name": "Local file inclusion exploit",
|
|
6242
|
+
"enabled": false,
|
|
6243
|
+
"tags": {
|
|
6244
|
+
"type": "lfi",
|
|
6245
|
+
"category": "vulnerability_trigger",
|
|
6246
|
+
"cwe": "22",
|
|
6247
|
+
"capec": "1000/255/153/126",
|
|
6248
|
+
"confidence": "0",
|
|
6249
|
+
"module": "rasp"
|
|
6250
|
+
},
|
|
6251
|
+
"conditions": [
|
|
6252
|
+
{
|
|
6253
|
+
"parameters": {
|
|
6254
|
+
"resource": [
|
|
6255
|
+
{
|
|
6256
|
+
"address": "server.io.fs.file"
|
|
6257
|
+
}
|
|
6258
|
+
],
|
|
6259
|
+
"params": [
|
|
6260
|
+
{
|
|
6261
|
+
"address": "server.request.query"
|
|
6262
|
+
},
|
|
6263
|
+
{
|
|
6264
|
+
"address": "server.request.body"
|
|
6265
|
+
},
|
|
6266
|
+
{
|
|
6267
|
+
"address": "server.request.path_params"
|
|
6268
|
+
},
|
|
6269
|
+
{
|
|
6270
|
+
"address": "grpc.server.request.message"
|
|
6271
|
+
},
|
|
6272
|
+
{
|
|
6273
|
+
"address": "graphql.server.all_resolvers"
|
|
6274
|
+
},
|
|
6275
|
+
{
|
|
6276
|
+
"address": "graphql.server.resolver"
|
|
6277
|
+
}
|
|
6278
|
+
]
|
|
6279
|
+
},
|
|
6280
|
+
"operator": "lfi_detector"
|
|
6281
|
+
}
|
|
6282
|
+
],
|
|
6283
|
+
"transformers": [],
|
|
6284
|
+
"on_match": [
|
|
6285
|
+
"stack_trace"
|
|
6286
|
+
]
|
|
6287
|
+
},
|
|
6288
|
+
{
|
|
6289
|
+
"id": "rasp-934-100",
|
|
6290
|
+
"name": "Server-side request forgery exploit",
|
|
6291
|
+
"enabled": false,
|
|
6292
|
+
"tags": {
|
|
6293
|
+
"type": "ssrf",
|
|
6294
|
+
"category": "vulnerability_trigger",
|
|
6295
|
+
"cwe": "918",
|
|
6296
|
+
"capec": "1000/225/115/664",
|
|
6297
|
+
"confidence": "0",
|
|
6298
|
+
"module": "rasp"
|
|
6299
|
+
},
|
|
6300
|
+
"conditions": [
|
|
6301
|
+
{
|
|
6302
|
+
"parameters": {
|
|
6303
|
+
"resource": [
|
|
6304
|
+
{
|
|
6305
|
+
"address": "server.io.net.url"
|
|
6306
|
+
}
|
|
6307
|
+
],
|
|
6308
|
+
"params": [
|
|
6309
|
+
{
|
|
6310
|
+
"address": "server.request.query"
|
|
6311
|
+
},
|
|
6312
|
+
{
|
|
6313
|
+
"address": "server.request.body"
|
|
6314
|
+
},
|
|
6315
|
+
{
|
|
6316
|
+
"address": "server.request.path_params"
|
|
6317
|
+
},
|
|
6318
|
+
{
|
|
6319
|
+
"address": "grpc.server.request.message"
|
|
6320
|
+
},
|
|
6321
|
+
{
|
|
6322
|
+
"address": "graphql.server.all_resolvers"
|
|
6323
|
+
},
|
|
6324
|
+
{
|
|
6325
|
+
"address": "graphql.server.resolver"
|
|
6326
|
+
}
|
|
6327
|
+
]
|
|
6328
|
+
},
|
|
6329
|
+
"operator": "ssrf_detector"
|
|
6330
|
+
}
|
|
6331
|
+
],
|
|
6332
|
+
"transformers": [],
|
|
6333
|
+
"on_match": [
|
|
6334
|
+
"stack_trace"
|
|
6335
|
+
]
|
|
6336
|
+
},
|
|
6337
|
+
{
|
|
6338
|
+
"id": "rasp-942-100",
|
|
6339
|
+
"name": "SQL injection exploit",
|
|
6340
|
+
"enabled": false,
|
|
6341
|
+
"tags": {
|
|
6342
|
+
"type": "sql_injection",
|
|
6343
|
+
"category": "vulnerability_trigger",
|
|
6344
|
+
"cwe": "89",
|
|
6345
|
+
"capec": "1000/152/248/66",
|
|
6346
|
+
"confidence": "0",
|
|
6347
|
+
"module": "rasp"
|
|
6348
|
+
},
|
|
6349
|
+
"conditions": [
|
|
6350
|
+
{
|
|
6351
|
+
"parameters": {
|
|
6352
|
+
"resource": [
|
|
6353
|
+
{
|
|
6354
|
+
"address": "server.db.statement"
|
|
6355
|
+
}
|
|
6356
|
+
],
|
|
6357
|
+
"params": [
|
|
6358
|
+
{
|
|
6359
|
+
"address": "server.request.query"
|
|
6360
|
+
},
|
|
6361
|
+
{
|
|
6362
|
+
"address": "server.request.body"
|
|
6363
|
+
},
|
|
6364
|
+
{
|
|
6365
|
+
"address": "server.request.path_params"
|
|
6366
|
+
},
|
|
6367
|
+
{
|
|
6368
|
+
"address": "graphql.server.all_resolvers"
|
|
6369
|
+
},
|
|
6370
|
+
{
|
|
6371
|
+
"address": "graphql.server.resolver"
|
|
6372
|
+
}
|
|
6373
|
+
],
|
|
6374
|
+
"db_type": [
|
|
6375
|
+
{
|
|
6376
|
+
"address": "server.db.system"
|
|
6377
|
+
}
|
|
6378
|
+
]
|
|
6379
|
+
},
|
|
6380
|
+
"operator": "sqli_detector"
|
|
6381
|
+
}
|
|
6382
|
+
],
|
|
6383
|
+
"transformers": [],
|
|
6384
|
+
"on_match": [
|
|
6385
|
+
"stack_trace"
|
|
6386
|
+
]
|
|
6387
|
+
},
|
|
6239
6388
|
{
|
|
6240
6389
|
"id": "sqr-000-001",
|
|
6241
6390
|
"name": "SSRF: Try to access the credential manager of the main cloud services",
|
|
@@ -8391,6 +8540,34 @@
|
|
|
8391
8540
|
}
|
|
8392
8541
|
],
|
|
8393
8542
|
"scanners": [
|
|
8543
|
+
{
|
|
8544
|
+
"id": "406f8606-52c4-4663-8db9-df70f9e8766c",
|
|
8545
|
+
"name": "ZIP Code",
|
|
8546
|
+
"key": {
|
|
8547
|
+
"operator": "match_regex",
|
|
8548
|
+
"parameters": {
|
|
8549
|
+
"regex": "\\b(?:zip|postal)\\b",
|
|
8550
|
+
"options": {
|
|
8551
|
+
"case_sensitive": false,
|
|
8552
|
+
"min_length": 3
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8555
|
+
},
|
|
8556
|
+
"value": {
|
|
8557
|
+
"operator": "match_regex",
|
|
8558
|
+
"parameters": {
|
|
8559
|
+
"regex": "^[0-9]{5}(?:-[0-9]{4})?$",
|
|
8560
|
+
"options": {
|
|
8561
|
+
"case_sensitive": true,
|
|
8562
|
+
"min_length": 5
|
|
8563
|
+
}
|
|
8564
|
+
}
|
|
8565
|
+
},
|
|
8566
|
+
"tags": {
|
|
8567
|
+
"type": "zipcode",
|
|
8568
|
+
"category": "address"
|
|
8569
|
+
}
|
|
8570
|
+
},
|
|
8394
8571
|
{
|
|
8395
8572
|
"id": "JU1sRk3mSzqSUJn6GrVn7g",
|
|
8396
8573
|
"name": "American Express Card Scanner (4+4+4+3 digits)",
|
|
@@ -9157,6 +9334,34 @@
|
|
|
9157
9334
|
"category": "payment"
|
|
9158
9335
|
}
|
|
9159
9336
|
},
|
|
9337
|
+
{
|
|
9338
|
+
"id": "18b608bd7a764bff5b2344c0",
|
|
9339
|
+
"name": "Phone number",
|
|
9340
|
+
"key": {
|
|
9341
|
+
"operator": "match_regex",
|
|
9342
|
+
"parameters": {
|
|
9343
|
+
"regex": "\\bphone|number|mobile\\b",
|
|
9344
|
+
"options": {
|
|
9345
|
+
"case_sensitive": false,
|
|
9346
|
+
"min_length": 3
|
|
9347
|
+
}
|
|
9348
|
+
}
|
|
9349
|
+
},
|
|
9350
|
+
"value": {
|
|
9351
|
+
"operator": "match_regex",
|
|
9352
|
+
"parameters": {
|
|
9353
|
+
"regex": "^(?:\\(\\+\\d{1,3}\\)|\\+\\d{1,3}|00\\d{1,3})?[-\\s\\.]?(?:\\(\\d{3}\\)[-\\s\\.]?)?(?:\\d[-\\s\\.]?){6,10}$",
|
|
9354
|
+
"options": {
|
|
9355
|
+
"case_sensitive": false,
|
|
9356
|
+
"min_length": 6
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
9359
|
+
},
|
|
9360
|
+
"tags": {
|
|
9361
|
+
"type": "phone",
|
|
9362
|
+
"category": "pii"
|
|
9363
|
+
}
|
|
9364
|
+
},
|
|
9160
9365
|
{
|
|
9161
9366
|
"id": "de0899e0cbaaa812bb624cf04c912071012f616d-mod",
|
|
9162
9367
|
"name": "UK National Insurance Number Scanner",
|