dd-trace 3.41.0 → 3.42.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.
Files changed (58) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +24 -0
  3. package/package.json +6 -5
  4. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  6. package/packages/datadog-instrumentations/src/http/client.js +22 -0
  7. package/packages/datadog-instrumentations/src/jest.js +11 -5
  8. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  9. package/packages/datadog-instrumentations/src/next.js +3 -1
  10. package/packages/datadog-instrumentations/src/restify.js +1 -1
  11. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  12. package/packages/datadog-plugin-http/src/client.js +19 -2
  13. package/packages/datadog-plugin-kafkajs/src/consumer.js +51 -0
  14. package/packages/datadog-plugin-kafkajs/src/producer.js +55 -0
  15. package/packages/datadog-plugin-next/src/index.js +7 -7
  16. package/packages/dd-trace/src/appsec/addresses.js +2 -1
  17. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  18. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  19. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  20. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  21. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  22. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  23. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  24. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  25. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  26. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  27. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  28. package/packages/dd-trace/src/appsec/index.js +13 -1
  29. package/packages/dd-trace/src/appsec/recommended.json +1395 -2
  30. package/packages/dd-trace/src/appsec/reporter.js +19 -0
  31. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +6 -3
  32. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  33. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
  34. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +75 -56
  35. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +15 -9
  36. package/packages/dd-trace/src/config.js +31 -2
  37. package/packages/dd-trace/src/datastreams/processor.js +107 -12
  38. package/packages/dd-trace/src/noop/proxy.js +4 -0
  39. package/packages/dd-trace/src/opentracing/span.js +2 -0
  40. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
  41. package/packages/dd-trace/src/plugins/index.js +1 -0
  42. package/packages/dd-trace/src/plugins/util/git.js +2 -2
  43. package/packages/dd-trace/src/plugins/util/test.js +3 -2
  44. package/packages/dd-trace/src/profiler.js +5 -3
  45. package/packages/dd-trace/src/profiling/config.js +8 -0
  46. package/packages/dd-trace/src/profiling/profiler.js +10 -4
  47. package/packages/dd-trace/src/profiling/profilers/events.js +166 -73
  48. package/packages/dd-trace/src/proxy.js +21 -1
  49. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  50. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  51. package/packages/dd-trace/src/spanleak.js +98 -0
  52. package/packages/dd-trace/src/startup-log.js +7 -1
  53. package/packages/dd-trace/src/telemetry/dependencies.js +55 -9
  54. package/packages/dd-trace/src/telemetry/index.js +135 -43
  55. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  56. package/packages/dd-trace/src/telemetry/send-data.js +47 -5
  57. package/packages/dd-trace/src/tracer.js +4 -0
  58. package/scripts/install_plugin_modules.js +11 -3
@@ -0,0 +1,105 @@
1
+ 'use strict'
2
+
3
+ const InjectionAnalyzer = require('./injection-analyzer')
4
+ const { HEADER_INJECTION } = require('../vulnerabilities')
5
+ const { getNodeModulesPaths } = require('../path-line')
6
+ const { HEADER_NAME_VALUE_SEPARATOR } = require('../vulnerabilities-formatter/constants')
7
+ const { getRanges } = require('../taint-tracking/operations')
8
+ const {
9
+ HTTP_REQUEST_COOKIE_NAME,
10
+ HTTP_REQUEST_COOKIE_VALUE,
11
+ HTTP_REQUEST_HEADER_VALUE
12
+ } = require('../taint-tracking/source-types')
13
+
14
+ const EXCLUDED_PATHS = getNodeModulesPaths('express')
15
+ const EXCLUDED_HEADER_NAMES = [
16
+ 'location',
17
+ 'sec-websocket-location',
18
+ 'sec-websocket-accept',
19
+ 'upgrade',
20
+ 'connection'
21
+ ]
22
+
23
+ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
24
+ constructor () {
25
+ super(HEADER_INJECTION)
26
+ }
27
+
28
+ onConfigure () {
29
+ this.addSub('datadog:http:server:response:set-header:finish', ({ name, value }) => {
30
+ if (Array.isArray(value)) {
31
+ for (let i = 0; i < value.length; i++) {
32
+ const headerValue = value[i]
33
+
34
+ this.analyze({ name, value: headerValue })
35
+ }
36
+ } else {
37
+ this.analyze({ name, value })
38
+ }
39
+ })
40
+ }
41
+
42
+ _isVulnerable ({ name, value }, iastContext) {
43
+ const lowerCasedHeaderName = name?.trim().toLowerCase()
44
+
45
+ if (this.isExcludedHeaderName(lowerCasedHeaderName) || typeof value !== 'string') return
46
+
47
+ const ranges = getRanges(iastContext, value)
48
+ if (ranges?.length > 0) {
49
+ return !(this.isCookieExclusion(lowerCasedHeaderName, ranges) ||
50
+ this.isSameHeaderExclusion(lowerCasedHeaderName, ranges) ||
51
+ this.isAccessControlAllowOriginExclusion(lowerCasedHeaderName, ranges))
52
+ }
53
+
54
+ return false
55
+ }
56
+
57
+ _getEvidence (headerInfo, iastContext) {
58
+ const prefix = headerInfo.name + HEADER_NAME_VALUE_SEPARATOR
59
+ const prefixLength = prefix.length
60
+
61
+ const evidence = super._getEvidence(headerInfo.value, iastContext)
62
+ evidence.value = prefix + evidence.value
63
+ evidence.ranges = evidence.ranges.map(range => {
64
+ return {
65
+ ...range,
66
+ start: range.start + prefixLength,
67
+ end: range.end + prefixLength
68
+ }
69
+ })
70
+
71
+ return evidence
72
+ }
73
+
74
+ isExcludedHeaderName (name) {
75
+ return EXCLUDED_HEADER_NAMES.includes(name)
76
+ }
77
+
78
+ isCookieExclusion (name, ranges) {
79
+ if (name === 'set-cookie') {
80
+ return ranges
81
+ .every(range => range.iinfo.type === HTTP_REQUEST_COOKIE_VALUE || range.iinfo.type === HTTP_REQUEST_COOKIE_NAME)
82
+ }
83
+
84
+ return false
85
+ }
86
+
87
+ isAccessControlAllowOriginExclusion (name, ranges) {
88
+ if (name === 'access-control-allow-origin') {
89
+ return ranges
90
+ .every(range => range.iinfo.type === HTTP_REQUEST_HEADER_VALUE)
91
+ }
92
+
93
+ return false
94
+ }
95
+
96
+ isSameHeaderExclusion (name, ranges) {
97
+ return ranges.length === 1 && name === ranges[0].iinfo.parameterName?.toLowerCase()
98
+ }
99
+
100
+ _getExcludedPaths () {
101
+ return EXCLUDED_PATHS
102
+ }
103
+ }
104
+
105
+ module.exports = new HeaderInjectionAnalyzer()
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const HEADER_NAME_VALUE_SEPARATOR = ': '
4
+
5
+ module.exports = {
6
+ HEADER_NAME_VALUE_SEPARATOR
7
+ }
@@ -3,27 +3,20 @@
3
3
  const iastLog = require('../../../iast-log')
4
4
 
5
5
  const COMMAND_PATTERN = '^(?:\\s*(?:sudo|doas)\\s+)?\\b\\S+\\b\\s(.*)'
6
+ const pattern = new RegExp(COMMAND_PATTERN, 'gmi')
6
7
 
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
8
+ module.exports = function extractSensitiveRanges (evidence) {
9
+ try {
10
+ pattern.lastIndex = 0
15
11
 
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)
12
+ const regexResult = pattern.exec(evidence.value)
13
+ if (regexResult && regexResult.length > 1) {
14
+ const start = regexResult.index + (regexResult[0].length - regexResult[1].length)
15
+ const end = start + regexResult[1].length
16
+ return [{ start, end }]
24
17
  }
25
- return []
18
+ } catch (e) {
19
+ iastLog.debug(e)
26
20
  }
21
+ return []
27
22
  }
28
-
29
- module.exports = CommandSensitiveAnalyzer
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ const { HEADER_NAME_VALUE_SEPARATOR } = require('../../constants')
4
+
5
+ module.exports = function extractSensitiveRanges (evidence, namePattern, valuePattern) {
6
+ const evidenceValue = evidence.value
7
+ const sections = evidenceValue.split(HEADER_NAME_VALUE_SEPARATOR)
8
+ const headerName = sections[0]
9
+ const headerValue = sections.slice(1).join(HEADER_NAME_VALUE_SEPARATOR)
10
+ namePattern.lastIndex = 0
11
+ valuePattern.lastIndex = 0
12
+ if (namePattern.test(headerName) || valuePattern.test(headerValue)) {
13
+ return [{
14
+ start: headerName.length + HEADER_NAME_VALUE_SEPARATOR.length,
15
+ end: evidenceValue.length
16
+ }]
17
+ }
18
+
19
+ return []
20
+ }
@@ -2,15 +2,11 @@
2
2
 
3
3
  const { stringifyWithRanges } = require('../../utils')
4
4
 
5
- class JsonSensitiveAnalyzer {
6
- extractSensitiveRanges (evidence) {
7
- // expect object evidence
8
- const { value, ranges, sensitiveRanges } = stringifyWithRanges(evidence.value, evidence.rangesToApply, true)
9
- evidence.value = value
10
- evidence.ranges = ranges
5
+ module.exports = function extractSensitiveRanges (evidence) {
6
+ // expect object evidence
7
+ const { value, ranges, sensitiveRanges } = stringifyWithRanges(evidence.value, evidence.rangesToApply, true)
8
+ evidence.value = value
9
+ evidence.ranges = ranges
11
10
 
12
- return sensitiveRanges
13
- }
11
+ return sensitiveRanges
14
12
  }
15
-
16
- module.exports = JsonSensitiveAnalyzer
@@ -3,33 +3,26 @@
3
3
  const iastLog = require('../../../iast-log')
4
4
 
5
5
  const LDAP_PATTERN = '\\(.*?(?:~=|=|<=|>=)(?<LITERAL>[^)]+)\\)'
6
+ const pattern = new RegExp(LDAP_PATTERN, 'gmi')
6
7
 
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 = []
8
+ module.exports = function extractSensitiveRanges (evidence) {
9
+ try {
10
+ pattern.lastIndex = 0
11
+ const tokens = []
16
12
 
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)
13
+ let regexResult = pattern.exec(evidence.value)
14
+ while (regexResult != null) {
15
+ if (!regexResult.groups.LITERAL) continue
16
+ // Computing indices manually since NodeJs 12 does not support d flag on regular expressions
17
+ // TODO Get indices from group by adding d flag in regular expression
18
+ const start = regexResult.index + (regexResult[0].length - regexResult.groups.LITERAL.length - 1)
19
+ const end = start + regexResult.groups.LITERAL.length
20
+ tokens.push({ start, end })
21
+ regexResult = pattern.exec(evidence.value)
30
22
  }
31
- return []
23
+ return tokens
24
+ } catch (e) {
25
+ iastLog.debug(e)
32
26
  }
27
+ return []
33
28
  }
34
-
35
- module.exports = LdapSensitiveAnalyzer
@@ -23,96 +23,90 @@ const NUMERIC_LITERAL =
23
23
  })`
24
24
  const ORACLE_ESCAPED_LITERAL = 'q\'<.*?>\'|q\'\\(.*?\\)\'|q\'\\{.*?\\}\'|q\'\\[.*?\\]\'|q\'(?<ESCAPE>.).*?\\k<ESCAPE>\''
25
25
 
26
- class SqlSensitiveAnalyzer {
27
- constructor () {
28
- this._patterns = {
29
- ANSI: new RegExp( // Default
30
- [
31
- NUMERIC_LITERAL,
32
- STRING_LITERAL,
33
- LINE_COMMENT,
34
- BLOCK_COMMENT
35
- ].join('|'),
36
- 'gmi'
37
- ),
38
- MYSQL: new RegExp(
39
- [
40
- NUMERIC_LITERAL,
41
- MYSQL_STRING_LITERAL,
42
- LINE_COMMENT,
43
- BLOCK_COMMENT
44
- ].join('|'),
45
- 'gmi'
46
- ),
47
- POSTGRES: new RegExp(
48
- [
49
- NUMERIC_LITERAL,
50
- POSTGRESQL_ESCAPED_LITERAL,
51
- STRING_LITERAL,
52
- LINE_COMMENT,
53
- BLOCK_COMMENT
54
- ].join('|'),
55
- 'gmi'
56
- ),
57
- ORACLE: new RegExp([
58
- NUMERIC_LITERAL,
59
- ORACLE_ESCAPED_LITERAL,
60
- STRING_LITERAL,
61
- LINE_COMMENT,
62
- BLOCK_COMMENT
63
- ].join('|'),
64
- 'gmi')
65
- }
66
- this._patterns.SQLITE = this._patterns.MYSQL
67
- this._patterns.MARIADB = this._patterns.MYSQL
68
- }
26
+ const patterns = {
27
+ ANSI: new RegExp( // Default
28
+ [
29
+ NUMERIC_LITERAL,
30
+ STRING_LITERAL,
31
+ LINE_COMMENT,
32
+ BLOCK_COMMENT
33
+ ].join('|'),
34
+ 'gmi'
35
+ ),
36
+ MYSQL: new RegExp(
37
+ [
38
+ NUMERIC_LITERAL,
39
+ MYSQL_STRING_LITERAL,
40
+ LINE_COMMENT,
41
+ BLOCK_COMMENT
42
+ ].join('|'),
43
+ 'gmi'
44
+ ),
45
+ POSTGRES: new RegExp(
46
+ [
47
+ NUMERIC_LITERAL,
48
+ POSTGRESQL_ESCAPED_LITERAL,
49
+ STRING_LITERAL,
50
+ LINE_COMMENT,
51
+ BLOCK_COMMENT
52
+ ].join('|'),
53
+ 'gmi'
54
+ ),
55
+ ORACLE: new RegExp([
56
+ NUMERIC_LITERAL,
57
+ ORACLE_ESCAPED_LITERAL,
58
+ STRING_LITERAL,
59
+ LINE_COMMENT,
60
+ BLOCK_COMMENT
61
+ ].join('|'),
62
+ 'gmi')
63
+ }
64
+ patterns.SQLITE = patterns.MYSQL
65
+ patterns.MARIADB = patterns.MYSQL
69
66
 
70
- extractSensitiveRanges (evidence) {
71
- try {
72
- let pattern = this._patterns[evidence.dialect]
73
- if (!pattern) {
74
- pattern = this._patterns['ANSI']
75
- }
76
- pattern.lastIndex = 0
77
- const tokens = []
67
+ module.exports = function extractSensitiveRanges (evidence) {
68
+ try {
69
+ let pattern = patterns[evidence.dialect]
70
+ if (!pattern) {
71
+ pattern = patterns['ANSI']
72
+ }
73
+ pattern.lastIndex = 0
74
+ const tokens = []
78
75
 
79
- let regexResult = pattern.exec(evidence.value)
80
- while (regexResult != null) {
81
- let start = regexResult.index
82
- let end = regexResult.index + regexResult[0].length
83
- const startChar = evidence.value.charAt(start)
84
- if (startChar === '\'' || startChar === '"') {
85
- start++
86
- end--
87
- } else if (end > start + 1) {
88
- const nextChar = evidence.value.charAt(start + 1)
89
- if (startChar === '/' && nextChar === '*') {
90
- start += 2
91
- end -= 2
92
- } else if (startChar === '-' && startChar === nextChar) {
93
- start += 2
94
- } else if (startChar.toLowerCase() === 'q' && nextChar === '\'') {
95
- start += 3
96
- end -= 2
97
- } else if (startChar === '$') {
98
- const match = regexResult[0]
99
- const size = match.indexOf('$', 1) + 1
100
- if (size > 1) {
101
- start += size
102
- end -= size
103
- }
76
+ let regexResult = pattern.exec(evidence.value)
77
+ while (regexResult != null) {
78
+ let start = regexResult.index
79
+ let end = regexResult.index + regexResult[0].length
80
+ const startChar = evidence.value.charAt(start)
81
+ if (startChar === '\'' || startChar === '"') {
82
+ start++
83
+ end--
84
+ } else if (end > start + 1) {
85
+ const nextChar = evidence.value.charAt(start + 1)
86
+ if (startChar === '/' && nextChar === '*') {
87
+ start += 2
88
+ end -= 2
89
+ } else if (startChar === '-' && startChar === nextChar) {
90
+ start += 2
91
+ } else if (startChar.toLowerCase() === 'q' && nextChar === '\'') {
92
+ start += 3
93
+ end -= 2
94
+ } else if (startChar === '$') {
95
+ const match = regexResult[0]
96
+ const size = match.indexOf('$', 1) + 1
97
+ if (size > 1) {
98
+ start += size
99
+ end -= size
104
100
  }
105
101
  }
106
-
107
- tokens.push({ start, end })
108
- regexResult = pattern.exec(evidence.value)
109
102
  }
110
- return tokens
111
- } catch (e) {
112
- iastLog.debug(e)
103
+
104
+ tokens.push({ start, end })
105
+ regexResult = pattern.exec(evidence.value)
113
106
  }
114
- return []
107
+ return tokens
108
+ } catch (e) {
109
+ iastLog.debug(e)
115
110
  }
111
+ return []
116
112
  }
117
-
118
- module.exports = SqlSensitiveAnalyzer
@@ -4,46 +4,37 @@ const iastLog = require('../../../iast-log')
4
4
 
5
5
  const AUTHORITY = '^(?:[^:]+:)?//([^@]+)@'
6
6
  const QUERY_FRAGMENT = '[?#&]([^=&;]+)=([^?#&]+)'
7
+ const pattern = new RegExp([AUTHORITY, QUERY_FRAGMENT].join('|'), 'gmi')
8
+
9
+ module.exports = function extractSensitiveRanges (evidence) {
10
+ try {
11
+ const ranges = []
12
+ let regexResult = pattern.exec(evidence.value)
13
+
14
+ while (regexResult != null) {
15
+ if (typeof regexResult[1] === 'string') {
16
+ // AUTHORITY regex match always ends by group + @
17
+ // it means that the match last chars - 1 are always the group
18
+ const end = regexResult.index + (regexResult[0].length - 1)
19
+ const start = end - regexResult[1].length
20
+ ranges.push({ start, end })
21
+ }
7
22
 
8
- class UrlSensitiveAnalyzer {
9
- constructor () {
10
- this._pattern = new RegExp([AUTHORITY, QUERY_FRAGMENT].join('|'), 'gmi')
11
- }
12
-
13
- extractSensitiveRanges (evidence) {
14
- try {
15
- const pattern = this._pattern
16
-
17
- const ranges = []
18
- let regexResult = pattern.exec(evidence.value)
19
-
20
- while (regexResult != null) {
21
- if (typeof regexResult[1] === 'string') {
22
- // AUTHORITY regex match always ends by group + @
23
- // it means that the match last chars - 1 are always the group
24
- const end = regexResult.index + (regexResult[0].length - 1)
25
- const start = end - regexResult[1].length
26
- ranges.push({ start, end })
27
- }
28
-
29
- if (typeof regexResult[3] === 'string') {
30
- // QUERY_FRAGMENT regex always ends with the group
31
- // it means that the match last chars are always the group
32
- const end = regexResult.index + regexResult[0].length
33
- const start = end - regexResult[3].length
34
- ranges.push({ start, end })
35
- }
36
-
37
- regexResult = pattern.exec(evidence.value)
23
+ if (typeof regexResult[3] === 'string') {
24
+ // QUERY_FRAGMENT regex always ends with the group
25
+ // it means that the match last chars are always the group
26
+ const end = regexResult.index + regexResult[0].length
27
+ const start = end - regexResult[3].length
28
+ ranges.push({ start, end })
38
29
  }
39
30
 
40
- return ranges
41
- } catch (e) {
42
- iastLog.debug(e)
31
+ regexResult = pattern.exec(evidence.value)
43
32
  }
44
33
 
45
- return []
34
+ return ranges
35
+ } catch (e) {
36
+ iastLog.debug(e)
46
37
  }
47
- }
48
38
 
49
- module.exports = UrlSensitiveAnalyzer
39
+ return []
40
+ }
@@ -5,11 +5,12 @@ const vulnerabilities = require('../../vulnerabilities')
5
5
 
6
6
  const { contains, intersects, remove } = require('./range-utils')
7
7
 
8
- const CommandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
9
- const JsonSensitiveAnalyzer = require('./sensitive-analyzers/json-sensitive-analyzer')
10
- const LdapSensitiveAnalyzer = require('./sensitive-analyzers/ldap-sensitive-analyzer')
11
- const SqlSensitiveAnalyzer = require('./sensitive-analyzers/sql-sensitive-analyzer')
12
- const UrlSensitiveAnalyzer = require('./sensitive-analyzers/url-sensitive-analyzer')
8
+ const commandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
9
+ const headerSensitiveAnalyzer = require('./sensitive-analyzers/header-sensitive-analyzer')
10
+ const jsonSensitiveAnalyzer = require('./sensitive-analyzers/json-sensitive-analyzer')
11
+ const ldapSensitiveAnalyzer = require('./sensitive-analyzers/ldap-sensitive-analyzer')
12
+ const sqlSensitiveAnalyzer = require('./sensitive-analyzers/sql-sensitive-analyzer')
13
+ const urlSensitiveAnalyzer = require('./sensitive-analyzers/url-sensitive-analyzer')
13
14
 
14
15
  const { DEFAULT_IAST_REDACTION_NAME_PATTERN, DEFAULT_IAST_REDACTION_VALUE_PATTERN } = require('./sensitive-regex')
15
16
 
@@ -21,13 +22,15 @@ class SensitiveHandler {
21
22
  this._valuePattern = new RegExp(DEFAULT_IAST_REDACTION_VALUE_PATTERN, 'gmi')
22
23
 
23
24
  this._sensitiveAnalyzers = new Map()
24
- this._sensitiveAnalyzers.set(vulnerabilities.COMMAND_INJECTION, new CommandSensitiveAnalyzer())
25
- this._sensitiveAnalyzers.set(vulnerabilities.NOSQL_MONGODB_INJECTION, new JsonSensitiveAnalyzer())
26
- this._sensitiveAnalyzers.set(vulnerabilities.LDAP_INJECTION, new LdapSensitiveAnalyzer())
27
- this._sensitiveAnalyzers.set(vulnerabilities.SQL_INJECTION, new SqlSensitiveAnalyzer())
28
- const urlSensitiveAnalyzer = new UrlSensitiveAnalyzer()
25
+ this._sensitiveAnalyzers.set(vulnerabilities.COMMAND_INJECTION, commandSensitiveAnalyzer)
26
+ this._sensitiveAnalyzers.set(vulnerabilities.NOSQL_MONGODB_INJECTION, jsonSensitiveAnalyzer)
27
+ this._sensitiveAnalyzers.set(vulnerabilities.LDAP_INJECTION, ldapSensitiveAnalyzer)
28
+ this._sensitiveAnalyzers.set(vulnerabilities.SQL_INJECTION, sqlSensitiveAnalyzer)
29
29
  this._sensitiveAnalyzers.set(vulnerabilities.SSRF, urlSensitiveAnalyzer)
30
30
  this._sensitiveAnalyzers.set(vulnerabilities.UNVALIDATED_REDIRECT, urlSensitiveAnalyzer)
31
+ this._sensitiveAnalyzers.set(vulnerabilities.HEADER_INJECTION, (evidence) => {
32
+ return headerSensitiveAnalyzer(evidence, this._namePattern, this._valuePattern)
33
+ })
31
34
  }
32
35
 
33
36
  isSensibleName (name) {
@@ -47,7 +50,7 @@ class SensitiveHandler {
47
50
  scrubEvidence (vulnerabilityType, evidence, sourcesIndexes, sources) {
48
51
  const sensitiveAnalyzer = this._sensitiveAnalyzers.get(vulnerabilityType)
49
52
  if (sensitiveAnalyzer) {
50
- const sensitiveRanges = sensitiveAnalyzer.extractSensitiveRanges(evidence)
53
+ const sensitiveRanges = sensitiveAnalyzer(evidence)
51
54
  return this.toRedactedJson(evidence, sensitiveRanges, sourcesIndexes, sources)
52
55
  }
53
56
  return null
@@ -1,6 +1,7 @@
1
1
  module.exports = {
2
2
  COMMAND_INJECTION: 'COMMAND_INJECTION',
3
3
  HARDCODED_SECRET: 'HARDCODED_SECRET',
4
+ HEADER_INJECTION: 'HEADER_INJECTION',
4
5
  HSTS_HEADER_MISSING: 'HSTS_HEADER_MISSING',
5
6
  INSECURE_COOKIE: 'INSECURE_COOKIE',
6
7
  LDAP_INJECTION: 'LDAP_INJECTION',
@@ -28,6 +28,14 @@ const { storage } = require('../../../datadog-core')
28
28
  let isEnabled = false
29
29
  let config
30
30
 
31
+ function sampleRequest ({ enabled, requestSampling }) {
32
+ if (!enabled || !requestSampling) {
33
+ return false
34
+ }
35
+
36
+ return Math.random() <= requestSampling
37
+ }
38
+
31
39
  function enable (_config) {
32
40
  if (isEnabled) return
33
41
 
@@ -90,6 +98,10 @@ function incomingHttpStartTranslator ({ req, res, abortController }) {
90
98
  payload[addresses.HTTP_CLIENT_IP] = clientIp
91
99
  }
92
100
 
101
+ if (sampleRequest(config.appsec.apiSecurity)) {
102
+ payload[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
103
+ }
104
+
93
105
  const actions = waf.run(payload, req)
94
106
 
95
107
  handleResults(actions, req, res, rootSpan, abortController)
@@ -101,7 +113,7 @@ function incomingHttpEndTranslator ({ req, res }) {
101
113
  delete responseHeaders['set-cookie']
102
114
 
103
115
  const payload = {
104
- [addresses.HTTP_INCOMING_RESPONSE_CODE]: res.statusCode,
116
+ [addresses.HTTP_INCOMING_RESPONSE_CODE]: '' + res.statusCode,
105
117
  [addresses.HTTP_INCOMING_RESPONSE_HEADERS]: responseHeaders
106
118
  }
107
119