dd-trace 4.18.0 → 5.6.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 (209) hide show
  1. package/CONTRIBUTING.md +98 -0
  2. package/LICENSE-3rdparty.csv +4 -5
  3. package/MIGRATING.md +15 -0
  4. package/README.md +20 -140
  5. package/ci/cypress/after-run.js +1 -0
  6. package/ci/cypress/after-spec.js +1 -0
  7. package/ci/init.js +1 -4
  8. package/ext/kinds.d.ts +1 -0
  9. package/ext/kinds.js +2 -1
  10. package/ext/tags.d.ts +2 -1
  11. package/ext/tags.js +6 -1
  12. package/index.d.ts +1523 -1460
  13. package/package.json +19 -19
  14. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  15. package/packages/datadog-core/src/utils/src/get.js +11 -0
  16. package/packages/datadog-core/src/utils/src/has.js +14 -0
  17. package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
  18. package/packages/datadog-core/src/utils/src/pick.js +11 -0
  19. package/packages/datadog-core/src/utils/src/set.js +16 -0
  20. package/packages/datadog-core/src/utils/src/uniq.js +5 -0
  21. package/packages/datadog-esbuild/index.js +1 -20
  22. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  23. package/packages/datadog-instrumentations/src/amqplib.js +2 -2
  24. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  25. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  26. package/packages/datadog-instrumentations/src/child_process.js +150 -0
  27. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  28. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  29. package/packages/datadog-instrumentations/src/cucumber.js +163 -46
  30. package/packages/datadog-instrumentations/src/dns.js +2 -1
  31. package/packages/datadog-instrumentations/src/express.js +20 -0
  32. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  33. package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
  34. package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
  35. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  36. package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
  37. package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
  38. package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
  39. package/packages/datadog-instrumentations/src/http/client.js +12 -2
  40. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  41. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  42. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  43. package/packages/datadog-instrumentations/src/jest.js +239 -52
  44. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  45. package/packages/datadog-instrumentations/src/mocha.js +154 -18
  46. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
  47. package/packages/datadog-instrumentations/src/mongoose.js +23 -10
  48. package/packages/datadog-instrumentations/src/mquery.js +65 -0
  49. package/packages/datadog-instrumentations/src/net.js +10 -2
  50. package/packages/datadog-instrumentations/src/next.js +35 -9
  51. package/packages/datadog-instrumentations/src/playwright.js +110 -16
  52. package/packages/datadog-instrumentations/src/restify.js +14 -1
  53. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  54. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  55. package/packages/datadog-plugin-amqplib/src/consumer.js +14 -1
  56. package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
  57. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
  58. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
  59. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
  60. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
  61. package/packages/datadog-plugin-child_process/src/index.js +91 -0
  62. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
  63. package/packages/datadog-plugin-cucumber/src/index.js +70 -13
  64. package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
  65. package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
  66. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
  67. package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
  68. package/packages/datadog-plugin-cypress/src/support.js +50 -3
  69. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
  70. package/packages/datadog-plugin-graphql/src/index.js +1 -6
  71. package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
  72. package/packages/datadog-plugin-grpc/src/client.js +16 -2
  73. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  74. package/packages/datadog-plugin-http/src/client.js +19 -2
  75. package/packages/datadog-plugin-jest/src/index.js +118 -12
  76. package/packages/datadog-plugin-jest/src/util.js +38 -16
  77. package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
  78. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
  79. package/packages/datadog-plugin-mocha/src/index.js +87 -17
  80. package/packages/datadog-plugin-next/src/index.js +40 -14
  81. package/packages/datadog-plugin-playwright/src/index.js +71 -8
  82. package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
  83. package/packages/datadog-plugin-rhea/src/producer.js +10 -0
  84. package/packages/dd-trace/src/appsec/activation.js +29 -0
  85. package/packages/dd-trace/src/appsec/addresses.js +5 -1
  86. package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -0
  87. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  88. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  89. package/packages/dd-trace/src/appsec/channels.js +7 -3
  90. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  91. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
  92. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
  93. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  94. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
  95. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
  96. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
  97. package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
  98. package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
  99. package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
  100. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  101. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
  102. package/packages/dd-trace/src/appsec/iast/index.js +15 -5
  103. package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
  104. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  105. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
  106. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
  107. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
  108. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
  109. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
  110. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
  111. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
  112. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
  113. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
  114. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  115. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  116. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  117. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  118. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  119. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  120. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  121. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  122. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  123. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
  124. package/packages/dd-trace/src/appsec/index.js +49 -33
  125. package/packages/dd-trace/src/appsec/recommended.json +1763 -106
  126. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
  127. package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
  128. package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
  129. package/packages/dd-trace/src/appsec/reporter.js +51 -34
  130. package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
  131. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  132. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  133. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  134. package/packages/dd-trace/src/ci-visibility/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
  135. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
  136. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  137. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
  138. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  139. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
  140. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
  141. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
  142. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
  143. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  144. package/packages/dd-trace/src/config.js +561 -470
  145. package/packages/dd-trace/src/data_streams_context.js +1 -1
  146. package/packages/dd-trace/src/datastreams/pathway.js +58 -1
  147. package/packages/dd-trace/src/datastreams/processor.js +196 -27
  148. package/packages/dd-trace/src/datastreams/writer.js +11 -5
  149. package/packages/dd-trace/src/dogstatsd.js +3 -5
  150. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
  151. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  152. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  153. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  154. package/packages/dd-trace/src/exporters/common/request.js +21 -3
  155. package/packages/dd-trace/src/format.js +30 -2
  156. package/packages/dd-trace/src/id.js +12 -0
  157. package/packages/dd-trace/src/iitm.js +1 -1
  158. package/packages/dd-trace/src/log/channels.js +1 -1
  159. package/packages/dd-trace/src/noop/proxy.js +4 -0
  160. package/packages/dd-trace/src/noop/span.js +1 -0
  161. package/packages/dd-trace/src/opentelemetry/span.js +104 -4
  162. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  163. package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
  164. package/packages/dd-trace/src/opentracing/span.js +48 -4
  165. package/packages/dd-trace/src/opentracing/span_context.js +15 -6
  166. package/packages/dd-trace/src/opentracing/tracer.js +4 -3
  167. package/packages/dd-trace/src/plugin_manager.js +1 -1
  168. package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
  169. package/packages/dd-trace/src/plugins/database.js +1 -1
  170. package/packages/dd-trace/src/plugins/index.js +7 -0
  171. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  172. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  173. package/packages/dd-trace/src/plugins/util/git.js +104 -22
  174. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  175. package/packages/dd-trace/src/plugins/util/test.js +60 -10
  176. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  177. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  178. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  179. package/packages/dd-trace/src/priority_sampler.js +30 -38
  180. package/packages/dd-trace/src/profiler.js +5 -3
  181. package/packages/dd-trace/src/profiling/config.js +77 -24
  182. package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
  183. package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
  184. package/packages/dd-trace/src/profiling/profiler.js +33 -22
  185. package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
  186. package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
  187. package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
  188. package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
  189. package/packages/dd-trace/src/proxy.js +56 -24
  190. package/packages/dd-trace/src/ritm.js +1 -1
  191. package/packages/dd-trace/src/sampling_rule.js +130 -0
  192. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  193. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  194. package/packages/dd-trace/src/span_processor.js +9 -1
  195. package/packages/dd-trace/src/span_sampler.js +6 -64
  196. package/packages/dd-trace/src/spanleak.js +98 -0
  197. package/packages/dd-trace/src/startup-log.js +7 -1
  198. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  199. package/packages/dd-trace/src/telemetry/index.js +182 -53
  200. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  201. package/packages/dd-trace/src/telemetry/send-data.js +65 -7
  202. package/packages/dd-trace/src/tracer.js +12 -5
  203. package/register.js +4 -0
  204. package/scripts/install_plugin_modules.js +11 -3
  205. package/scripts/st.js +105 -0
  206. package/packages/datadog-instrumentations/src/child-process.js +0 -30
  207. package/packages/dd-trace/src/plugins/util/exec.js +0 -13
  208. package/packages/diagnostics_channel/index.js +0 -3
  209. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+ const Analyzer = require('./vulnerability-analyzer')
3
+ const { WEAK_RANDOMNESS } = require('../vulnerabilities')
4
+
5
+ class WeakRandomnessAnalyzer extends Analyzer {
6
+ constructor () {
7
+ super(WEAK_RANDOMNESS)
8
+ }
9
+
10
+ onConfigure () {
11
+ this.addSub('datadog:random:call', ({ fn }) => this.analyze(fn))
12
+ }
13
+
14
+ _isVulnerable (fn) {
15
+ return fn === Math.random
16
+ }
17
+ }
18
+
19
+ module.exports = new WeakRandomnessAnalyzer()
@@ -0,0 +1,90 @@
1
+ 'use strict'
2
+
3
+ const { storage } = require('../../../../../datadog-core')
4
+ const iastContextFunctions = require('../iast-context')
5
+ const overheadController = require('../overhead-controller')
6
+ const { IastPlugin } = require('../iast-plugin')
7
+ const { IAST_ENABLED_TAG_KEY } = require('../tags')
8
+ const { createTransaction, removeTransaction } = require('../taint-tracking/operations')
9
+ const vulnerabilityReporter = require('../vulnerability-reporter')
10
+ const { TagKey } = require('../telemetry/iast-metric')
11
+
12
+ class IastContextPlugin extends IastPlugin {
13
+ startCtxOn (channelName, tag) {
14
+ super.addSub(channelName, (message) => this.startContext())
15
+
16
+ this._getAndRegisterSubscription({
17
+ channelName,
18
+ tag,
19
+ tagKey: TagKey.SOURCE_TYPE
20
+ })
21
+ }
22
+
23
+ finishCtxOn (channelName) {
24
+ super.addSub(channelName, (message) => this.finishContext())
25
+ }
26
+
27
+ getRootSpan (store) {
28
+ return store?.span
29
+ }
30
+
31
+ getTopContext () {
32
+ return {}
33
+ }
34
+
35
+ newIastContext (rootSpan) {
36
+ return { rootSpan }
37
+ }
38
+
39
+ addIastEnabledTag (isRequestAcquired, rootSpan) {
40
+ if (rootSpan?.addTags) {
41
+ rootSpan.addTags({
42
+ [IAST_ENABLED_TAG_KEY]: isRequestAcquired ? 1 : 0
43
+ })
44
+ }
45
+ }
46
+
47
+ startContext () {
48
+ let isRequestAcquired = false
49
+ let iastContext
50
+
51
+ const store = storage.getStore()
52
+ if (store) {
53
+ const topContext = this.getTopContext()
54
+ const rootSpan = this.getRootSpan(store)
55
+
56
+ isRequestAcquired = overheadController.acquireRequest(rootSpan)
57
+ if (isRequestAcquired) {
58
+ iastContext = iastContextFunctions.saveIastContext(store, topContext, this.newIastContext(rootSpan))
59
+ createTransaction(rootSpan.context().toSpanId(), iastContext)
60
+ overheadController.initializeRequestContext(iastContext)
61
+ }
62
+ this.addIastEnabledTag(isRequestAcquired, rootSpan)
63
+ }
64
+
65
+ return {
66
+ isRequestAcquired,
67
+ iastContext,
68
+ store
69
+ }
70
+ }
71
+
72
+ finishContext () {
73
+ const store = storage.getStore()
74
+ if (store) {
75
+ const topContext = this.getTopContext()
76
+ const iastContext = iastContextFunctions.getIastContext(store, topContext)
77
+ const rootSpan = iastContext?.rootSpan
78
+ if (iastContext && rootSpan) {
79
+ vulnerabilityReporter.sendVulnerabilities(iastContext.vulnerabilities, rootSpan)
80
+ removeTransaction(iastContext)
81
+ }
82
+
83
+ if (iastContextFunctions.cleanIastContext(store, topContext, iastContext)) {
84
+ overheadController.releaseRequest()
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ module.exports = IastContextPlugin
@@ -0,0 +1,14 @@
1
+ 'use strict'
2
+
3
+ const { KAFKA_MESSAGE_KEY, KAFKA_MESSAGE_VALUE } = require('../taint-tracking/source-types')
4
+ const IastContextPlugin = require('./context-plugin')
5
+
6
+ class KafkaContextPlugin extends IastContextPlugin {
7
+ onConfigure () {
8
+ this.startCtxOn('dd-trace:kafkajs:consumer:afterStart', [KAFKA_MESSAGE_KEY, KAFKA_MESSAGE_VALUE])
9
+
10
+ this.finishCtxOn('dd-trace:kafkajs:consumer:beforeFinish')
11
+ }
12
+ }
13
+
14
+ module.exports = new KafkaContextPlugin()
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const dc = require('../../../../diagnostics_channel')
3
+ const dc = require('dc-polyfill')
4
4
  const log = require('../../log')
5
5
  const { calculateDDBasePath } = require('../../util')
6
6
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
 
5
5
  const iastLog = require('./iast-log')
6
6
  const Plugin = require('../../plugins/plugin')
@@ -101,6 +101,14 @@ class IastPlugin extends Plugin {
101
101
  }
102
102
  }
103
103
 
104
+ enable () {
105
+ this.configure(true)
106
+ }
107
+
108
+ disable () {
109
+ this.configure(false)
110
+ }
111
+
104
112
  onConfigure () {}
105
113
 
106
114
  configure (config) {
@@ -127,10 +135,13 @@ class IastPlugin extends Plugin {
127
135
  if (!channelName && !moduleName) return
128
136
 
129
137
  if (!moduleName) {
130
- const firstSep = channelName.indexOf(':')
138
+ let firstSep = channelName.indexOf(':')
131
139
  if (firstSep === -1) {
132
140
  moduleName = channelName
133
141
  } else {
142
+ if (channelName.startsWith('tracing:')) {
143
+ firstSep = channelName.indexOf(':', 'tracing:'.length + 1)
144
+ }
134
145
  const lastSep = channelName.indexOf(':', firstSep + 1)
135
146
  moduleName = channelName.substring(firstSep + 1, lastSep !== -1 ? lastSep : channelName.length)
136
147
  }
@@ -3,7 +3,7 @@ const { enableAllAnalyzers, disableAllAnalyzers } = require('./analyzers')
3
3
  const web = require('../../plugins/util/web')
4
4
  const { storage } = require('../../../../datadog-core')
5
5
  const overheadController = require('./overhead-controller')
6
- const dc = require('../../../../diagnostics_channel')
6
+ const dc = require('dc-polyfill')
7
7
  const iastContextFunctions = require('./iast-context')
8
8
  const {
9
9
  enableTaintTracking,
@@ -21,8 +21,12 @@ const requestStart = dc.channel('dd-trace:incomingHttpRequestStart')
21
21
  const requestClose = dc.channel('dd-trace:incomingHttpRequestEnd')
22
22
  const iastResponseEnd = dc.channel('datadog:iast:response-end')
23
23
 
24
+ let isEnabled = false
25
+
24
26
  function enable (config, _tracer) {
25
- iastTelemetry.configure(config, config.iast && config.iast.telemetryVerbosity)
27
+ if (isEnabled) return
28
+
29
+ iastTelemetry.configure(config, config.iast?.telemetryVerbosity)
26
30
  enableAllAnalyzers(config)
27
31
  enableTaintTracking(config.iast, iastTelemetry.verbosity)
28
32
  requestStart.subscribe(onIncomingHttpRequestStart)
@@ -30,9 +34,15 @@ function enable (config, _tracer) {
30
34
  overheadController.configure(config.iast)
31
35
  overheadController.startGlobalContext()
32
36
  vulnerabilityReporter.start(config, _tracer)
37
+
38
+ isEnabled = true
33
39
  }
34
40
 
35
41
  function disable () {
42
+ if (!isEnabled) return
43
+
44
+ isEnabled = false
45
+
36
46
  iastTelemetry.stop()
37
47
  disableAllAnalyzers()
38
48
  disableTaintTracking()
@@ -43,7 +53,7 @@ function disable () {
43
53
  }
44
54
 
45
55
  function onIncomingHttpRequestStart (data) {
46
- if (data && data.req) {
56
+ if (data?.req) {
47
57
  const store = storage.getStore()
48
58
  if (store) {
49
59
  const topContext = web.getContext(data.req)
@@ -68,11 +78,11 @@ function onIncomingHttpRequestStart (data) {
68
78
  }
69
79
 
70
80
  function onIncomingHttpRequestEnd (data) {
71
- if (data && data.req) {
81
+ if (data?.req) {
72
82
  const store = storage.getStore()
73
83
  const topContext = web.getContext(data.req)
74
84
  const iastContext = iastContextFunctions.getIastContext(store, topContext)
75
- if (iastContext && iastContext.rootSpan) {
85
+ if (iastContext?.rootSpan) {
76
86
  iastResponseEnd.publish(data)
77
87
 
78
88
  const vulnerabilities = iastContext.vulnerabilities
@@ -52,7 +52,7 @@ function _resetGlobalContext () {
52
52
  }
53
53
 
54
54
  function acquireRequest (rootSpan) {
55
- if (availableRequest > 0) {
55
+ if (availableRequest > 0 && rootSpan) {
56
56
  const sampling = config && typeof config.requestSampling === 'number'
57
57
  ? config.requestSampling : 30
58
58
  if (rootSpan.context().toSpanId().slice(-2) <= sampling) {
@@ -13,7 +13,7 @@ const pathLine = {
13
13
  }
14
14
 
15
15
  const EXCLUDED_PATHS = [
16
- path.join(path.sep, 'node_modules', 'diagnostics_channel')
16
+ path.join(path.sep, 'node_modules', 'dc-polyfill')
17
17
  ]
18
18
  const EXCLUDED_PATH_PREFIXES = [
19
19
  'node:diagnostics_channel',
@@ -2,7 +2,9 @@
2
2
 
3
3
  const csiMethods = [
4
4
  { src: 'concat' },
5
+ { src: 'parse' },
5
6
  { src: 'plusOperator', operator: true },
7
+ { src: 'random' },
6
8
  { src: 'replace' },
7
9
  { src: 'slice' },
8
10
  { src: 'substr' },
@@ -10,18 +10,28 @@ const {
10
10
  } = require('./operations')
11
11
 
12
12
  const taintTrackingPlugin = require('./plugin')
13
+ const kafkaConsumerPlugin = require('./plugins/kafka')
14
+
15
+ const kafkaContextPlugin = require('../context/kafka-ctx-plugin')
13
16
 
14
17
  module.exports = {
15
18
  enableTaintTracking (config, telemetryVerbosity) {
16
19
  enableRewriter(telemetryVerbosity)
17
20
  enableTaintOperations(telemetryVerbosity)
18
21
  taintTrackingPlugin.enable()
22
+
23
+ kafkaContextPlugin.enable()
24
+ kafkaConsumerPlugin.enable()
25
+
19
26
  setMaxTransactions(config.maxConcurrentRequests)
20
27
  },
21
28
  disableTaintTracking () {
22
29
  disableRewriter()
23
30
  disableTaintOperations()
24
31
  taintTrackingPlugin.disable()
32
+
33
+ kafkaContextPlugin.disable()
34
+ kafkaConsumerPlugin.disable()
25
35
  },
26
36
  setMaxTransactions: setMaxTransactions,
27
37
  createTransaction: createTransaction,
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const TaintedUtils = require('@datadog/native-iast-taint-tracking')
4
+ const { IAST_TRANSACTION_ID } = require('../iast-context')
5
+ const iastLog = require('../iast-log')
6
+
7
+ function taintObject (iastContext, object, type, keyTainting, keyType) {
8
+ let result = object
9
+ const transactionId = iastContext?.[IAST_TRANSACTION_ID]
10
+ if (transactionId) {
11
+ const queue = [{ parent: null, property: null, value: object }]
12
+ const visited = new WeakSet()
13
+
14
+ while (queue.length > 0) {
15
+ const { parent, property, value, key } = queue.pop()
16
+ if (value === null) {
17
+ continue
18
+ }
19
+
20
+ try {
21
+ if (typeof value === 'string') {
22
+ const tainted = TaintedUtils.newTaintedString(transactionId, value, property, type)
23
+ if (!parent) {
24
+ result = tainted
25
+ } else if (keyTainting && key) {
26
+ const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType)
27
+ parent[taintedProperty] = tainted
28
+ } else {
29
+ parent[key] = tainted
30
+ }
31
+ } else if (typeof value === 'object' && !visited.has(value)) {
32
+ visited.add(value)
33
+
34
+ for (const key of Object.keys(value)) {
35
+ queue.push({ parent: value, property: property ? `${property}.${key}` : key, value: value[key], key })
36
+ }
37
+
38
+ if (parent && keyTainting && key) {
39
+ const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType)
40
+ parent[taintedProperty] = value
41
+ }
42
+ }
43
+ } catch (e) {
44
+ iastLog.error(`Error visiting property : ${property}`).errorAndPublish(e)
45
+ }
46
+ }
47
+ }
48
+ return result
49
+ }
50
+
51
+ module.exports = {
52
+ taintObject
53
+ }
@@ -2,11 +2,11 @@
2
2
 
3
3
  const TaintedUtils = require('@datadog/native-iast-taint-tracking')
4
4
  const { IAST_TRANSACTION_ID } = require('../iast-context')
5
- const iastLog = require('../iast-log')
6
5
  const iastTelemetry = require('../telemetry')
7
6
  const { REQUEST_TAINTED } = require('../telemetry/iast-metric')
8
7
  const { isInfoAllowed } = require('../telemetry/verbosity')
9
8
  const { getTaintTrackingImpl, getTaintTrackingNoop } = require('./taint-tracking-impl')
9
+ const { taintObject } = require('./operations-taint-object')
10
10
 
11
11
  function createTransaction (id, iastContext) {
12
12
  if (id && iastContext) {
@@ -34,7 +34,7 @@ function removeTransaction (iastContext) {
34
34
  }
35
35
 
36
36
  function newTaintedString (iastContext, string, name, type) {
37
- let result = string
37
+ let result
38
38
  const transactionId = iastContext?.[IAST_TRANSACTION_ID]
39
39
  if (transactionId) {
40
40
  result = TaintedUtils.newTaintedString(transactionId, string, name, type)
@@ -44,56 +44,19 @@ function newTaintedString (iastContext, string, name, type) {
44
44
  return result
45
45
  }
46
46
 
47
- function taintObject (iastContext, object, type, keyTainting, keyType) {
48
- let result = object
47
+ function newTaintedObject (iastContext, obj, name, type) {
48
+ let result
49
49
  const transactionId = iastContext?.[IAST_TRANSACTION_ID]
50
50
  if (transactionId) {
51
- const queue = [{ parent: null, property: null, value: object }]
52
- const visited = new WeakSet()
53
-
54
- while (queue.length > 0) {
55
- const { parent, property, value, key } = queue.pop()
56
- if (value === null) {
57
- continue
58
- }
59
-
60
- try {
61
- if (typeof value === 'string') {
62
- const tainted = TaintedUtils.newTaintedString(transactionId, value, property, type)
63
- if (!parent) {
64
- result = tainted
65
- } else {
66
- if (keyTainting && key) {
67
- const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType)
68
- parent[taintedProperty] = tainted
69
- } else {
70
- parent[key] = tainted
71
- }
72
- }
73
- } else if (typeof value === 'object' && !visited.has(value)) {
74
- visited.add(value)
75
-
76
- const keys = Object.keys(value)
77
- for (let i = 0; i < keys.length; i++) {
78
- const key = keys[i]
79
- queue.push({ parent: value, property: property ? `${property}.${key}` : key, value: value[key], key })
80
- }
81
-
82
- if (parent && keyTainting && key) {
83
- const taintedProperty = TaintedUtils.newTaintedString(transactionId, key, property, keyType)
84
- parent[taintedProperty] = value
85
- }
86
- }
87
- } catch (e) {
88
- iastLog.error(`Error visiting property : ${property}`).errorAndPublish(e)
89
- }
90
- }
51
+ result = TaintedUtils.newTaintedObject(transactionId, obj, name, type)
52
+ } else {
53
+ result = obj
91
54
  }
92
55
  return result
93
56
  }
94
57
 
95
58
  function isTainted (iastContext, string) {
96
- let result = false
59
+ let result
97
60
  const transactionId = iastContext?.[IAST_TRANSACTION_ID]
98
61
  if (transactionId) {
99
62
  result = TaintedUtils.isTainted(transactionId, string)
@@ -104,7 +67,7 @@ function isTainted (iastContext, string) {
104
67
  }
105
68
 
106
69
  function getRanges (iastContext, string) {
107
- let result = []
70
+ let result
108
71
  const transactionId = iastContext?.[IAST_TRANSACTION_ID]
109
72
  if (transactionId) {
110
73
  result = TaintedUtils.getRanges(transactionId, string)
@@ -148,6 +111,7 @@ module.exports = {
148
111
  createTransaction,
149
112
  removeTransaction,
150
113
  newTaintedString,
114
+ newTaintedObject,
151
115
  taintObject,
152
116
  isTainted,
153
117
  getRanges,
@@ -3,7 +3,7 @@
3
3
  const { SourceIastPlugin } = require('../iast-plugin')
4
4
  const { getIastContext } = require('../iast-context')
5
5
  const { storage } = require('../../../../../datadog-core')
6
- const { taintObject, newTaintedString } = require('./operations')
6
+ const { taintObject, newTaintedString, getRanges } = require('./operations')
7
7
  const {
8
8
  HTTP_REQUEST_BODY,
9
9
  HTTP_REQUEST_COOKIE_VALUE,
@@ -65,6 +65,18 @@ class TaintTrackingPlugin extends SourceIastPlugin {
65
65
  }
66
66
  )
67
67
 
68
+ this.addSub(
69
+ { channelName: 'apm:graphql:resolve:start', tag: HTTP_REQUEST_BODY },
70
+ (data) => {
71
+ const iastContext = getIastContext(storage.getStore())
72
+ const source = data.context?.source
73
+ const ranges = source && getRanges(iastContext, source)
74
+ if (ranges?.length) {
75
+ this._taintTrackingHandler(ranges[0].iinfo.type, data.args, null, iastContext)
76
+ }
77
+ }
78
+ )
79
+
68
80
  // this is a special case to increment INSTRUMENTED_SOURCE metric for header
69
81
  this.addInstrumentedSource('http', [HTTP_REQUEST_HEADER_VALUE, HTTP_REQUEST_HEADER_NAME])
70
82
  }
@@ -104,14 +116,6 @@ class TaintTrackingPlugin extends SourceIastPlugin {
104
116
  this.taintHeaders(req.headers, iastContext)
105
117
  this.taintUrl(req, iastContext)
106
118
  }
107
-
108
- enable () {
109
- this.configure(true)
110
- }
111
-
112
- disable () {
113
- this.configure(false)
114
- }
115
119
  }
116
120
 
117
121
  module.exports = new TaintTrackingPlugin()
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../../../../../datadog-shimmer')
4
+ const { storage } = require('../../../../../../datadog-core')
5
+ const { getIastContext } = require('../../iast-context')
6
+ const { KAFKA_MESSAGE_KEY, KAFKA_MESSAGE_VALUE } = require('../source-types')
7
+ const { newTaintedObject, newTaintedString } = require('../operations')
8
+ const { SourceIastPlugin } = require('../../iast-plugin')
9
+
10
+ class KafkaConsumerIastPlugin extends SourceIastPlugin {
11
+ onConfigure () {
12
+ this.addSub({ channelName: 'dd-trace:kafkajs:consumer:afterStart', tag: [KAFKA_MESSAGE_KEY, KAFKA_MESSAGE_VALUE] },
13
+ ({ message }) => this.taintKafkaMessage(message)
14
+ )
15
+ }
16
+
17
+ getToStringWrap (toString, iastContext, type) {
18
+ return function () {
19
+ const res = toString.apply(this, arguments)
20
+ return newTaintedString(iastContext, res, undefined, type)
21
+ }
22
+ }
23
+
24
+ taintKafkaMessage (message) {
25
+ const iastContext = getIastContext(storage.getStore())
26
+
27
+ if (iastContext && message) {
28
+ const { key, value } = message
29
+
30
+ if (key && typeof key === 'object') {
31
+ shimmer.wrap(key, 'toString',
32
+ toString => this.getToStringWrap(toString, iastContext, KAFKA_MESSAGE_KEY))
33
+
34
+ newTaintedObject(iastContext, key, undefined, KAFKA_MESSAGE_KEY)
35
+ }
36
+
37
+ if (value && typeof value === 'object') {
38
+ shimmer.wrap(value, 'toString',
39
+ toString => this.getToStringWrap(toString, iastContext, KAFKA_MESSAGE_VALUE))
40
+
41
+ newTaintedObject(iastContext, value, undefined, KAFKA_MESSAGE_VALUE)
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ module.exports = new KafkaConsumerIastPlugin()
@@ -7,7 +7,7 @@ const { isPrivateModule, isNotLibraryFile } = require('./filter')
7
7
  const { csiMethods } = require('./csi-methods')
8
8
  const { getName } = require('../telemetry/verbosity')
9
9
  const { getRewriteFunction } = require('./rewriter-telemetry')
10
- const dc = require('../../../../../diagnostics_channel')
10
+ const dc = require('dc-polyfill')
11
11
 
12
12
  const hardcodedSecretCh = dc.channel('datadog:secrets:result')
13
13
  let rewriter
@@ -65,16 +65,18 @@ function getRewriter (telemetryVerbosity) {
65
65
  return rewriter
66
66
  }
67
67
 
68
- let originalPrepareStackTrace = Error.prepareStackTrace
68
+ let originalPrepareStackTrace
69
+ let actualPrepareStackTrace
69
70
  function getPrepareStackTraceAccessor () {
70
- let actual = getPrepareStackTrace(originalPrepareStackTrace)
71
+ originalPrepareStackTrace = Error.prepareStackTrace
72
+ actualPrepareStackTrace = getPrepareStackTrace(originalPrepareStackTrace)
71
73
  return {
72
74
  configurable: true,
73
75
  get () {
74
- return actual
76
+ return actualPrepareStackTrace
75
77
  },
76
78
  set (value) {
77
- actual = getPrepareStackTrace(value)
79
+ actualPrepareStackTrace = getPrepareStackTrace(value)
78
80
  originalPrepareStackTrace = value
79
81
  }
80
82
  }
@@ -121,7 +123,18 @@ function enableRewriter (telemetryVerbosity) {
121
123
 
122
124
  function disableRewriter () {
123
125
  shimmer.unwrap(Module.prototype, '_compile')
124
- Error.prepareStackTrace = originalPrepareStackTrace
126
+
127
+ if (!actualPrepareStackTrace) return
128
+
129
+ try {
130
+ delete Error.prepareStackTrace
131
+
132
+ Error.prepareStackTrace = originalPrepareStackTrace
133
+
134
+ actualPrepareStackTrace = undefined
135
+ } catch (e) {
136
+ iastLog.warn(e)
137
+ }
125
138
  }
126
139
 
127
140
  function getOriginalPathAndLineFromSourceMap ({ path, line, column }) {
@@ -9,5 +9,7 @@ module.exports = {
9
9
  HTTP_REQUEST_PARAMETER: 'http.request.parameter',
10
10
  HTTP_REQUEST_PATH: 'http.request.path',
11
11
  HTTP_REQUEST_PATH_PARAM: 'http.request.path.parameter',
12
- HTTP_REQUEST_URI: 'http.request.uri'
12
+ HTTP_REQUEST_URI: 'http.request.uri',
13
+ KAFKA_MESSAGE_KEY: 'kafka.message.key',
14
+ KAFKA_MESSAGE_VALUE: 'kafka.message.value'
13
15
  }
@@ -1,18 +1,26 @@
1
1
  'use strict'
2
2
 
3
+ const dc = require('dc-polyfill')
3
4
  const TaintedUtils = require('@datadog/native-iast-taint-tracking')
4
5
  const { storage } = require('../../../../../datadog-core')
5
6
  const iastContextFunctions = require('../iast-context')
6
7
  const iastLog = require('../iast-log')
7
8
  const { EXECUTED_PROPAGATION } = require('../telemetry/iast-metric')
8
9
  const { isDebugAllowed } = require('../telemetry/verbosity')
10
+ const { taintObject } = require('./operations-taint-object')
11
+
12
+ const mathRandomCallCh = dc.channel('datadog:random:call')
13
+
14
+ const JSON_VALUE = 'json.value'
9
15
 
10
16
  function noop (res) { return res }
11
17
  // NOTE: methods of this object must be synchronized with csi-methods.js file definitions!
12
18
  // Otherwise you may end up rewriting a method and not providing its rewritten implementation
13
19
  const TaintTrackingNoop = {
14
- plusOperator: noop,
15
20
  concat: noop,
21
+ parse: noop,
22
+ plusOperator: noop,
23
+ random: noop,
16
24
  replace: noop,
17
25
  slice: noop,
18
26
  substr: noop,
@@ -22,7 +30,7 @@ const TaintTrackingNoop = {
22
30
  }
23
31
 
24
32
  function getTransactionId (iastContext) {
25
- return iastContext && iastContext[iastContextFunctions.IAST_TRANSACTION_ID]
33
+ return iastContext?.[iastContextFunctions.IAST_TRANSACTION_ID]
26
34
  }
27
35
 
28
36
  function getContextDefault () {
@@ -110,7 +118,37 @@ function csiMethodsOverrides (getContext) {
110
118
  getContext,
111
119
  String.prototype.trim,
112
120
  String.prototype.trimStart
113
- )
121
+ ),
122
+
123
+ random: function (res, fn) {
124
+ if (mathRandomCallCh.hasSubscribers) {
125
+ mathRandomCallCh.publish({ fn })
126
+ }
127
+ return res
128
+ },
129
+
130
+ parse: function (res, fn, target, json) {
131
+ if (fn === JSON.parse) {
132
+ try {
133
+ const iastContext = getContext()
134
+ const transactionId = getTransactionId(iastContext)
135
+ if (transactionId) {
136
+ const ranges = TaintedUtils.getRanges(transactionId, json)
137
+
138
+ // TODO: first version.
139
+ // here we are losing the original source because taintObject always creates a new tainted
140
+ if (ranges?.length > 0) {
141
+ const range = ranges.find(range => range.iinfo?.type)
142
+ res = taintObject(iastContext, res, range?.iinfo.type || JSON_VALUE)
143
+ }
144
+ }
145
+ } catch (e) {
146
+ iastLog.error(e)
147
+ }
148
+ }
149
+
150
+ return res
151
+ }
114
152
  }
115
153
  }
116
154