dd-trace 4.0.0-pre-5e89884 → 4.0.0-pre-4e7da80
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/index.d.ts +16 -0
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/jest.js +1 -0
- package/packages/datadog-instrumentations/src/next.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -0
- package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +4 -2
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +4 -3
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +8 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +7 -1
- package/packages/datadog-plugin-http/src/client.js +2 -1
- package/packages/datadog-plugin-http2/src/client.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +22 -5
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +40 -4
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +2 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +2 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/range-utils.js +37 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +29 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +35 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +95 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +144 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +113 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +8 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -76
- package/packages/dd-trace/src/config.js +44 -7
- package/packages/dd-trace/src/constants.js +3 -1
- package/packages/dd-trace/src/git_metadata_tagger.js +17 -0
- package/packages/dd-trace/src/plugins/util/ci.js +62 -7
- package/packages/dd-trace/src/plugins/util/tags.js +5 -1
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/serverless.js +25 -0
- package/packages/dd-trace/src/span_processor.js +3 -0
- package/packages/dd-trace/src/tracer.js +9 -0
- package/version.js +9 -0
package/index.d.ts
CHANGED
|
@@ -77,6 +77,10 @@ export declare interface Tracer extends opentracing.Tracer {
|
|
|
77
77
|
* span will finish when that callback is called.
|
|
78
78
|
* * The function doesn't accept a callback and doesn't return a promise, in
|
|
79
79
|
* which case the span will finish at the end of the function execution.
|
|
80
|
+
*
|
|
81
|
+
* If the `orphanable` option is set to false, the function will not be traced
|
|
82
|
+
* unless there is already an active span or `childOf` option. Note that this
|
|
83
|
+
* option is deprecated and has been removed in version 4.0.
|
|
80
84
|
*/
|
|
81
85
|
trace<T> (name: string, fn: (span?: Span, fn?: (error?: Error) => any) => T): T;
|
|
82
86
|
trace<T> (name: string, options: TraceOptions & SpanOptions, fn: (span?: Span, done?: (error?: Error) => string) => T): T;
|
|
@@ -440,6 +444,11 @@ export declare interface TracerOptions {
|
|
|
440
444
|
* Whether to enable vulnerability deduplication
|
|
441
445
|
*/
|
|
442
446
|
deduplicationEnabled?: boolean
|
|
447
|
+
/**
|
|
448
|
+
* Whether to enable vulnerability redaction
|
|
449
|
+
* @default true
|
|
450
|
+
*/
|
|
451
|
+
redactionEnabled?: boolean
|
|
443
452
|
}
|
|
444
453
|
};
|
|
445
454
|
|
|
@@ -485,6 +494,13 @@ export declare interface TracerOptions {
|
|
|
485
494
|
*/
|
|
486
495
|
logLevel?: 'error' | 'debug'
|
|
487
496
|
|
|
497
|
+
/**
|
|
498
|
+
* If false, require a parent in order to trace.
|
|
499
|
+
* @default true
|
|
500
|
+
* @deprecated since version 4.0
|
|
501
|
+
*/
|
|
502
|
+
orphanable?: boolean
|
|
503
|
+
|
|
488
504
|
/**
|
|
489
505
|
* Enables DBM to APM link using tag injection.
|
|
490
506
|
* @default 'disabled'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.0.0-pre-
|
|
3
|
+
"version": "4.0.0-pre-4e7da80",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"test:integration:cucumber": "mocha --colors --timeout 30000 \"integration-tests/cucumber/*.spec.js\"",
|
|
37
37
|
"test:integration:cypress": "mocha --colors --timeout 30000 \"integration-tests/cypress/*.spec.js\"",
|
|
38
38
|
"test:integration:playwright": "mocha --colors --timeout 30000 \"integration-tests/playwright/*.spec.js\"",
|
|
39
|
+
"test:integration:serverless": "mocha --colors --timeout 30000 \"integration-tests/serverless/*.spec.js\"",
|
|
39
40
|
"test:shimmer": "mocha --colors 'packages/datadog-shimmer/test/**/*.spec.js'",
|
|
40
41
|
"test:shimmer:ci": "nyc --no-clean --include 'packages/datadog-shimmer/src/**/*.js' -- npm run test:shimmer",
|
|
41
42
|
"leak:core": "node ./scripts/install_plugin_modules && (cd packages/memwatch && yarn) && NODE_PATH=./packages/memwatch/node_modules node --no-warnings ./node_modules/.bin/tape 'packages/dd-trace/test/leak/**/*.js'",
|
|
@@ -67,9 +68,9 @@
|
|
|
67
68
|
"dependencies": {
|
|
68
69
|
"@datadog/native-appsec": "^3.1.0",
|
|
69
70
|
"@datadog/native-iast-rewriter": "2.0.1",
|
|
70
|
-
"@datadog/native-iast-taint-tracking": "^1.4.
|
|
71
|
-
"@datadog/native-metrics": "^
|
|
72
|
-
"@datadog/pprof": "^2.2.
|
|
71
|
+
"@datadog/native-iast-taint-tracking": "^1.4.1",
|
|
72
|
+
"@datadog/native-metrics": "^2.0.0",
|
|
73
|
+
"@datadog/pprof": "^2.2.1",
|
|
73
74
|
"@datadog/sketches-js": "^2.1.0",
|
|
74
75
|
"crypto-randomuuid": "^1.0.0",
|
|
75
76
|
"diagnostics_channel": "^1.1.0",
|
|
@@ -454,6 +454,7 @@ addHook({
|
|
|
454
454
|
}, jestConfigSyncWrapper)
|
|
455
455
|
|
|
456
456
|
function jasmineAsyncInstallWraper (jasmineAsyncInstallExport, jestVersion) {
|
|
457
|
+
log.warn('jest-jasmine2 support is removed from dd-trace@v4. Consider changing to jest-circus as `testRunner`.')
|
|
457
458
|
return function (globalConfig, globalInput) {
|
|
458
459
|
globalInput._ddtrace = global._ddtrace
|
|
459
460
|
shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
6
6
|
const shimmer = require('../../datadog-shimmer')
|
|
7
|
+
const { MAJOR } = require('../../../version')
|
|
7
8
|
|
|
8
9
|
const startChannel = channel('apm:next:request:start')
|
|
9
10
|
const finishChannel = channel('apm:next:request:finish')
|
|
@@ -168,7 +169,11 @@ addHook({ name: 'next', versions: ['>=11.1 <13.2'], file: 'dist/server/next-serv
|
|
|
168
169
|
return nextServer
|
|
169
170
|
})
|
|
170
171
|
|
|
171
|
-
addHook({
|
|
172
|
+
addHook({
|
|
173
|
+
name: 'next',
|
|
174
|
+
versions: MAJOR >= 4 ? ['>=10.2 <11.1'] : ['>=9.5 <11.1'],
|
|
175
|
+
file: 'dist/next-server/server/next-server.js'
|
|
176
|
+
}, nextServer => {
|
|
172
177
|
const Server = nextServer.default
|
|
173
178
|
|
|
174
179
|
shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
|
|
@@ -38,6 +38,8 @@ class BaseAwsSdkPlugin extends Plugin {
|
|
|
38
38
|
'service.name': serviceName,
|
|
39
39
|
'aws.operation': operation,
|
|
40
40
|
'aws.region': awsRegion,
|
|
41
|
+
'region': awsRegion,
|
|
42
|
+
'aws_service': awsService,
|
|
41
43
|
'aws.service': awsService,
|
|
42
44
|
'component': 'aws-sdk'
|
|
43
45
|
}
|
|
@@ -60,6 +62,7 @@ class BaseAwsSdkPlugin extends Plugin {
|
|
|
60
62
|
const { span } = store
|
|
61
63
|
if (!span) return
|
|
62
64
|
span.setTag('aws.region', region)
|
|
65
|
+
span.setTag('region', region)
|
|
63
66
|
})
|
|
64
67
|
|
|
65
68
|
this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response }) => {
|
|
@@ -12,7 +12,8 @@ class CloudwatchLogs extends BaseAwsSdkPlugin {
|
|
|
12
12
|
|
|
13
13
|
return Object.assign(tags, {
|
|
14
14
|
'resource.name': `${operation} ${params.logGroupName}`,
|
|
15
|
-
'aws.cloudwatch.logs.log_group_name': params.logGroupName
|
|
15
|
+
'aws.cloudwatch.logs.log_group_name': params.logGroupName,
|
|
16
|
+
'loggroupname': params.logGroupName
|
|
16
17
|
})
|
|
17
18
|
}
|
|
18
19
|
}
|
|
@@ -12,7 +12,8 @@ class DynamoDb extends BaseAwsSdkPlugin {
|
|
|
12
12
|
if (params.TableName) {
|
|
13
13
|
Object.assign(tags, {
|
|
14
14
|
'resource.name': `${operation} ${params.TableName}`,
|
|
15
|
-
'aws.dynamodb.table_name': params.TableName
|
|
15
|
+
'aws.dynamodb.table_name': params.TableName,
|
|
16
|
+
'tablename': params.TableName
|
|
16
17
|
})
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -27,7 +28,8 @@ class DynamoDb extends BaseAwsSdkPlugin {
|
|
|
27
28
|
// also add span type to match serverless convention
|
|
28
29
|
Object.assign(tags, {
|
|
29
30
|
'resource.name': `${operation} ${tableName}`,
|
|
30
|
-
'aws.dynamodb.table_name': tableName
|
|
31
|
+
'aws.dynamodb.table_name': tableName,
|
|
32
|
+
'tablename': tableName
|
|
31
33
|
})
|
|
32
34
|
}
|
|
33
35
|
}
|
|
@@ -7,10 +7,11 @@ class EventBridge extends BaseAwsSdkPlugin {
|
|
|
7
7
|
|
|
8
8
|
generateTags (params, operation, response) {
|
|
9
9
|
if (!params || !params.source) return {}
|
|
10
|
-
|
|
10
|
+
const rulename = params.Name ? params.Name : ''
|
|
11
11
|
return {
|
|
12
|
-
'resource.name': `${operation} ${params.source}
|
|
13
|
-
'aws.eventbridge.source': params.source
|
|
12
|
+
'resource.name': operation ? `${operation} ${params.source}` : params.source,
|
|
13
|
+
'aws.eventbridge.source': `${params.source}`,
|
|
14
|
+
'rulename': `${rulename}`
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -12,7 +12,8 @@ class Redshift extends BaseAwsSdkPlugin {
|
|
|
12
12
|
|
|
13
13
|
return Object.assign(tags, {
|
|
14
14
|
'resource.name': `${operation} ${params.ClusterIdentifier}`,
|
|
15
|
-
'aws.redshift.cluster_identifier': params.ClusterIdentifier
|
|
15
|
+
'aws.redshift.cluster_identifier': params.ClusterIdentifier,
|
|
16
|
+
'clusteridentifier': params.ClusterIdentifier
|
|
16
17
|
})
|
|
17
18
|
}
|
|
18
19
|
}
|
|
@@ -9,10 +9,17 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
9
9
|
if (!params) return {}
|
|
10
10
|
|
|
11
11
|
if (!params.TopicArn && !(response.data && response.data.TopicArn)) return {}
|
|
12
|
+
const TopicArn = params.TopicArn || response.data.TopicArn
|
|
13
|
+
// Split the ARN into its parts
|
|
14
|
+
// ex.'arn:aws:sns:us-east-1:123456789012:my-topic'
|
|
15
|
+
const arnParts = TopicArn.split(':')
|
|
12
16
|
|
|
17
|
+
// Get the topic name from the last part of the ARN
|
|
18
|
+
const topicName = arnParts[arnParts.length - 1]
|
|
13
19
|
return {
|
|
14
20
|
'resource.name': `${operation} ${params.TopicArn || response.data.TopicArn}`,
|
|
15
|
-
'aws.sns.topic_arn':
|
|
21
|
+
'aws.sns.topic_arn': TopicArn,
|
|
22
|
+
'topicname': topicName
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
// TODO: should arn be sanitized or quantized in some way here,
|
|
@@ -59,10 +59,16 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
59
59
|
const tags = {}
|
|
60
60
|
|
|
61
61
|
if (!params || (!params.QueueName && !params.QueueUrl)) return tags
|
|
62
|
+
// 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue';
|
|
63
|
+
let queueName = params.QueueName
|
|
64
|
+
if (params.QueueUrl) {
|
|
65
|
+
queueName = params.QueueUrl.split('/')[params.QueueUrl.split('/').length - 1]
|
|
66
|
+
}
|
|
62
67
|
|
|
63
68
|
Object.assign(tags, {
|
|
64
69
|
'resource.name': `${operation} ${params.QueueName || params.QueueUrl}`,
|
|
65
|
-
'aws.sqs.queue_name': params.QueueName || params.QueueUrl
|
|
70
|
+
'aws.sqs.queue_name': params.QueueName || params.QueueUrl,
|
|
71
|
+
'queuename': queueName
|
|
66
72
|
})
|
|
67
73
|
|
|
68
74
|
switch (operation) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const InjectionAnalyzer = require('./injection-analyzer')
|
|
3
|
+
const { COMMAND_INJECTION } = require('../vulnerabilities')
|
|
3
4
|
|
|
4
5
|
class CommandInjectionAnalyzer extends InjectionAnalyzer {
|
|
5
6
|
constructor () {
|
|
6
|
-
super(
|
|
7
|
+
super(COMMAND_INJECTION)
|
|
7
8
|
this.addSub('datadog:child_process:execution:start', ({ command }) => this.analyze(command))
|
|
8
9
|
}
|
|
9
10
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const InjectionAnalyzer = require('./injection-analyzer')
|
|
3
|
+
const { LDAP_INJECTION } = require('../vulnerabilities')
|
|
3
4
|
|
|
4
5
|
class LdapInjectionAnalyzer extends InjectionAnalyzer {
|
|
5
6
|
constructor () {
|
|
6
|
-
super(
|
|
7
|
+
super(LDAP_INJECTION)
|
|
7
8
|
this.addSub('datadog:ldapjs:client:search', ({ base, filter }) => this.analyzeAll(base, filter))
|
|
8
9
|
}
|
|
9
10
|
}
|
|
@@ -4,10 +4,11 @@ const path = require('path')
|
|
|
4
4
|
const { getIastContext } = require('../iast-context')
|
|
5
5
|
const { storage } = require('../../../../../datadog-core')
|
|
6
6
|
const InjectionAnalyzer = require('./injection-analyzer')
|
|
7
|
+
const { PATH_TRAVERSAL } = require('../vulnerabilities')
|
|
7
8
|
|
|
8
9
|
class PathTraversalAnalyzer extends InjectionAnalyzer {
|
|
9
10
|
constructor () {
|
|
10
|
-
super(
|
|
11
|
+
super(PATH_TRAVERSAL)
|
|
11
12
|
this.addSub('apm:fs:operation:start', obj => {
|
|
12
13
|
const pathArguments = []
|
|
13
14
|
if (obj.dest) {
|
|
@@ -40,13 +41,29 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
|
|
|
40
41
|
this.analyze(pathArguments)
|
|
41
42
|
})
|
|
42
43
|
|
|
43
|
-
this.exclusionList = [
|
|
44
|
+
this.exclusionList = [
|
|
45
|
+
path.join('node_modules', 'send') + path.sep
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
this.internalExclusionList = [
|
|
49
|
+
'node:fs',
|
|
50
|
+
'node:internal/fs',
|
|
51
|
+
'node:internal\\fs',
|
|
52
|
+
'fs.js',
|
|
53
|
+
'internal/fs',
|
|
54
|
+
'internal\\fs'
|
|
55
|
+
]
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
_isExcluded (location) {
|
|
47
|
-
let ret =
|
|
59
|
+
let ret = true
|
|
48
60
|
if (location && location.path) {
|
|
49
|
-
|
|
61
|
+
// Exclude from reporting those vulnerabilities which location is from an internal fs call
|
|
62
|
+
if (location.isInternal) {
|
|
63
|
+
ret = this.internalExclusionList.some(elem => location.path.includes(elem))
|
|
64
|
+
} else {
|
|
65
|
+
ret = this.exclusionList.some(elem => location.path.includes(elem))
|
|
66
|
+
}
|
|
50
67
|
}
|
|
51
68
|
return ret
|
|
52
69
|
}
|
|
@@ -59,7 +76,7 @@ class PathTraversalAnalyzer extends InjectionAnalyzer {
|
|
|
59
76
|
|
|
60
77
|
if (value && value.constructor === Array) {
|
|
61
78
|
for (const val of value) {
|
|
62
|
-
if (this._isVulnerable(val, iastContext)) {
|
|
79
|
+
if (this._isVulnerable(val, iastContext) && this._checkOCE(iastContext)) {
|
|
63
80
|
this._report(val, iastContext)
|
|
64
81
|
// no support several evidences in the same vulnerability, just report the 1st one
|
|
65
82
|
break
|
|
@@ -1,12 +1,48 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
2
3
|
const InjectionAnalyzer = require('./injection-analyzer')
|
|
4
|
+
const { SQL_INJECTION } = require('../vulnerabilities')
|
|
5
|
+
const { getRanges } = require('../taint-tracking/operations')
|
|
6
|
+
const { storage } = require('../../../../../datadog-core')
|
|
7
|
+
const { getIastContext } = require('../iast-context')
|
|
8
|
+
const { createVulnerability, addVulnerability } = require('../vulnerability-reporter')
|
|
3
9
|
|
|
4
10
|
class SqlInjectionAnalyzer extends InjectionAnalyzer {
|
|
5
11
|
constructor () {
|
|
6
|
-
super(
|
|
7
|
-
this.addSub('apm:mysql:query:start', ({ sql }) => this.analyze(sql))
|
|
8
|
-
this.addSub('apm:mysql2:query:start', ({ sql }) => this.analyze(sql))
|
|
9
|
-
this.addSub('apm:pg:query:start', ({ query }) => this.analyze(query.text))
|
|
12
|
+
super(SQL_INJECTION)
|
|
13
|
+
this.addSub('apm:mysql:query:start', ({ sql }) => this.analyze(sql, 'MYSQL'))
|
|
14
|
+
this.addSub('apm:mysql2:query:start', ({ sql }) => this.analyze(sql, 'MYSQL'))
|
|
15
|
+
this.addSub('apm:pg:query:start', ({ query }) => this.analyze(query.text, 'POSTGRES'))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_getEvidence (value, iastContext, dialect) {
|
|
19
|
+
const ranges = getRanges(iastContext, value)
|
|
20
|
+
return { value, ranges, dialect }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
analyze (value, dialect) {
|
|
24
|
+
const store = storage.getStore()
|
|
25
|
+
const iastContext = getIastContext(store)
|
|
26
|
+
if (store && !iastContext) return
|
|
27
|
+
this._reportIfVulnerable(value, iastContext, dialect)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_reportIfVulnerable (value, context, dialect) {
|
|
31
|
+
if (this._isVulnerable(value, context) && this._checkOCE(context)) {
|
|
32
|
+
this._report(value, context, dialect)
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_report (value, context, dialect) {
|
|
39
|
+
const evidence = this._getEvidence(value, context, dialect)
|
|
40
|
+
const location = this._getLocation()
|
|
41
|
+
if (!this._isExcluded(location)) {
|
|
42
|
+
const spanId = context && context.rootSpan && context.rootSpan.context().toSpanId()
|
|
43
|
+
const vulnerability = createVulnerability(this._type, evidence, spanId, location)
|
|
44
|
+
addVulnerability(context, vulnerability)
|
|
45
|
+
}
|
|
10
46
|
}
|
|
11
47
|
}
|
|
12
48
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const Analyzer = require('./vulnerability-analyzer')
|
|
3
|
+
const { WEAK_CIPHER } = require('../vulnerabilities')
|
|
3
4
|
|
|
4
5
|
const INSECURE_CIPHERS = new Set([
|
|
5
6
|
'des', 'des-cbc', 'des-cfb', 'des-cfb1', 'des-cfb8', 'des-ecb', 'des-ede', 'des-ede-cbc', 'des-ede-cfb',
|
|
@@ -12,7 +13,7 @@ const INSECURE_CIPHERS = new Set([
|
|
|
12
13
|
|
|
13
14
|
class WeakCipherAnalyzer extends Analyzer {
|
|
14
15
|
constructor () {
|
|
15
|
-
super(
|
|
16
|
+
super(WEAK_CIPHER)
|
|
16
17
|
this.addSub('datadog:crypto:cipher:start', ({ algorithm }) => this.analyze(algorithm))
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const Analyzer = require('./vulnerability-analyzer')
|
|
3
|
+
const { WEAK_HASH } = require('../vulnerabilities')
|
|
3
4
|
|
|
4
5
|
const INSECURE_HASH_ALGORITHMS = new Set([
|
|
5
6
|
'md4', 'md4WithRSAEncryption', 'RSA-MD4',
|
|
@@ -9,7 +10,7 @@ const INSECURE_HASH_ALGORITHMS = new Set([
|
|
|
9
10
|
|
|
10
11
|
class WeakHashAnalyzer extends Analyzer {
|
|
11
12
|
constructor () {
|
|
12
|
-
super(
|
|
13
|
+
super(WEAK_HASH)
|
|
13
14
|
this.addSub('datadog:crypto:hashing:start', ({ algorithm }) => this.analyze(algorithm))
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -45,7 +45,8 @@ function getFirstNonDDPathAndLineFromCallsites (callsites) {
|
|
|
45
45
|
if (!isExcluded(callsite) && filepath.indexOf(pathLine.ddBasePath) === -1) {
|
|
46
46
|
return {
|
|
47
47
|
path: path.relative(process.cwd(), filepath),
|
|
48
|
-
line: callsite.getLineNumber()
|
|
48
|
+
line: callsite.getLineNumber(),
|
|
49
|
+
isInternal: !path.isAbsolute(filepath)
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function contains (rangeContainer, rangeContained) {
|
|
4
|
+
if (rangeContainer.start > rangeContained.start) {
|
|
5
|
+
return false
|
|
6
|
+
}
|
|
7
|
+
return rangeContainer.end >= rangeContained.end
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function intersects (rangeA, rangeB) {
|
|
11
|
+
return rangeB.start < rangeA.end && rangeB.end > rangeA.start
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function remove (range, rangeToRemove) {
|
|
15
|
+
if (!intersects(range, rangeToRemove)) {
|
|
16
|
+
return [range]
|
|
17
|
+
} else if (contains(rangeToRemove, range)) {
|
|
18
|
+
return []
|
|
19
|
+
} else {
|
|
20
|
+
const result = []
|
|
21
|
+
if (rangeToRemove.start > range.start) {
|
|
22
|
+
const offset = rangeToRemove.start - range.start
|
|
23
|
+
result.push({ start: range.start, end: range.start + offset })
|
|
24
|
+
}
|
|
25
|
+
if (rangeToRemove.end < range.end) {
|
|
26
|
+
const offset = range.end - rangeToRemove.end
|
|
27
|
+
result.push({ start: rangeToRemove.end, end: rangeToRemove.end + offset })
|
|
28
|
+
}
|
|
29
|
+
return result
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
contains,
|
|
35
|
+
intersects,
|
|
36
|
+
remove
|
|
37
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const iastLog = require('../../../iast-log')
|
|
4
|
+
|
|
5
|
+
const COMMAND_PATTERN = '^(?:\\s*(?:sudo|doas)\\s+)?\\b\\S+\\b(.*)'
|
|
6
|
+
|
|
7
|
+
class CommandSensitiveAnalyzer {
|
|
8
|
+
constructor () {
|
|
9
|
+
this._pattern = new RegExp(COMMAND_PATTERN, 'gmi')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
extractSensitiveRanges (evidence) {
|
|
13
|
+
try {
|
|
14
|
+
this._pattern.lastIndex = 0
|
|
15
|
+
|
|
16
|
+
const regexResult = this._pattern.exec(evidence.value)
|
|
17
|
+
if (regexResult && regexResult.length > 1) {
|
|
18
|
+
const start = regexResult.index + (regexResult[0].length - regexResult[1].length)
|
|
19
|
+
const end = start + regexResult[1].length
|
|
20
|
+
return [{ start, end }]
|
|
21
|
+
}
|
|
22
|
+
} catch (e) {
|
|
23
|
+
iastLog.debug(e)
|
|
24
|
+
}
|
|
25
|
+
return []
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = CommandSensitiveAnalyzer
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const iastLog = require('../../../iast-log')
|
|
4
|
+
|
|
5
|
+
const LDAP_PATTERN = '\\(.*?(?:~=|=|<=|>=)(?<LITERAL>[^)]+)\\)'
|
|
6
|
+
|
|
7
|
+
class LdapSensitiveAnalyzer {
|
|
8
|
+
constructor () {
|
|
9
|
+
this._pattern = new RegExp(LDAP_PATTERN, 'gmi')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
extractSensitiveRanges (evidence) {
|
|
13
|
+
try {
|
|
14
|
+
this._pattern.lastIndex = 0
|
|
15
|
+
const tokens = []
|
|
16
|
+
|
|
17
|
+
let regexResult = this._pattern.exec(evidence.value)
|
|
18
|
+
while (regexResult != null) {
|
|
19
|
+
if (!regexResult.groups.LITERAL) continue
|
|
20
|
+
// Computing indices manually since NodeJs 12 does not support d flag on regular expressions
|
|
21
|
+
// TODO Get indices from group by adding d flag in regular expression
|
|
22
|
+
const start = regexResult.index + (regexResult[0].length - regexResult.groups.LITERAL.length - 1)
|
|
23
|
+
const end = start + regexResult.groups.LITERAL.length
|
|
24
|
+
tokens.push({ start, end })
|
|
25
|
+
regexResult = this._pattern.exec(evidence.value)
|
|
26
|
+
}
|
|
27
|
+
return tokens
|
|
28
|
+
} catch (e) {
|
|
29
|
+
iastLog.debug(e)
|
|
30
|
+
}
|
|
31
|
+
return []
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = LdapSensitiveAnalyzer
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const iastLog = require('../../../iast-log')
|
|
4
|
+
|
|
5
|
+
const STRING_LITERAL = '\'(?:\'\'|[^\'])*\''
|
|
6
|
+
const POSTGRESQL_ESCAPED_LITERAL = '\\$([^$]*)\\$.*?\\$\\1\\$'
|
|
7
|
+
const MYSQL_STRING_LITERAL = '"(?:\\\\"|[^"])*"|\'(?:\\\\\'|[^\'])*\''
|
|
8
|
+
const LINE_COMMENT = '--.*$'
|
|
9
|
+
const BLOCK_COMMENT = '/\\*[\\s\\S]*\\*/'
|
|
10
|
+
const EXPONENT = '(?:E[-+]?\\d+[fd]?)?'
|
|
11
|
+
const INTEGER_NUMBER = '(?<!\\w)\\d+'
|
|
12
|
+
const DECIMAL_NUMBER = '\\d*\\.\\d+'
|
|
13
|
+
const HEX_NUMBER = 'x\'[0-9a-f]+\'|0x[0-9a-f]+'
|
|
14
|
+
const BIN_NUMBER = 'b\'[0-9a-f]+\'|0b[0-9a-f]+'
|
|
15
|
+
const NUMERIC_LITERAL =
|
|
16
|
+
`[-+]?(?:${
|
|
17
|
+
[
|
|
18
|
+
HEX_NUMBER,
|
|
19
|
+
BIN_NUMBER,
|
|
20
|
+
DECIMAL_NUMBER + EXPONENT,
|
|
21
|
+
INTEGER_NUMBER + EXPONENT
|
|
22
|
+
].join('|')
|
|
23
|
+
})`
|
|
24
|
+
|
|
25
|
+
class SqlSensitiveAnalyzer {
|
|
26
|
+
constructor () {
|
|
27
|
+
this._patterns = {
|
|
28
|
+
MYSQL: new RegExp(
|
|
29
|
+
[
|
|
30
|
+
NUMERIC_LITERAL,
|
|
31
|
+
MYSQL_STRING_LITERAL,
|
|
32
|
+
LINE_COMMENT,
|
|
33
|
+
BLOCK_COMMENT
|
|
34
|
+
].join('|'),
|
|
35
|
+
'gmi'
|
|
36
|
+
),
|
|
37
|
+
POSTGRES: new RegExp(
|
|
38
|
+
[
|
|
39
|
+
NUMERIC_LITERAL,
|
|
40
|
+
POSTGRESQL_ESCAPED_LITERAL,
|
|
41
|
+
STRING_LITERAL,
|
|
42
|
+
LINE_COMMENT,
|
|
43
|
+
BLOCK_COMMENT
|
|
44
|
+
].join('|'),
|
|
45
|
+
'gmi'
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
extractSensitiveRanges (evidence) {
|
|
51
|
+
try {
|
|
52
|
+
const pattern = this._patterns[evidence.dialect]
|
|
53
|
+
pattern.lastIndex = 0
|
|
54
|
+
const tokens = []
|
|
55
|
+
|
|
56
|
+
let regexResult = pattern.exec(evidence.value)
|
|
57
|
+
while (regexResult != null) {
|
|
58
|
+
let start = regexResult.index
|
|
59
|
+
let end = regexResult.index + regexResult[0].length
|
|
60
|
+
const startChar = evidence.value.charAt(start)
|
|
61
|
+
if (startChar === '\'' || startChar === '"') {
|
|
62
|
+
start++
|
|
63
|
+
end--
|
|
64
|
+
} else if (end > start + 1) {
|
|
65
|
+
const nextChar = evidence.value.charAt(start + 1)
|
|
66
|
+
if (startChar === '/' && nextChar === '*') {
|
|
67
|
+
start += 2
|
|
68
|
+
end -= 2
|
|
69
|
+
} else if (startChar === '-' && startChar === nextChar) {
|
|
70
|
+
start += 2
|
|
71
|
+
} else if (startChar.toLowerCase() === 'q' && nextChar === '\'') {
|
|
72
|
+
start += 3
|
|
73
|
+
end -= 2
|
|
74
|
+
} else if (startChar === '$') {
|
|
75
|
+
const match = regexResult[0]
|
|
76
|
+
const size = match.indexOf('$', 1) + 1
|
|
77
|
+
if (size > 1) {
|
|
78
|
+
start += size
|
|
79
|
+
end -= size
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
tokens.push({ start, end })
|
|
85
|
+
regexResult = pattern.exec(evidence.value)
|
|
86
|
+
}
|
|
87
|
+
return tokens
|
|
88
|
+
} catch (e) {
|
|
89
|
+
iastLog.debug(e)
|
|
90
|
+
}
|
|
91
|
+
return []
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = SqlSensitiveAnalyzer
|