dd-trace 4.51.1 → 4.53.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 (172) hide show
  1. package/LICENSE-3rdparty.csv +8 -2
  2. package/ci/init.js +16 -0
  3. package/index.d.ts +31 -13
  4. package/init.js +4 -66
  5. package/initialize.mjs +13 -10
  6. package/loader-hook.mjs +4 -0
  7. package/package.json +16 -11
  8. package/packages/datadog-core/src/storage.js +39 -2
  9. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  10. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  11. package/packages/datadog-instrumentations/src/cucumber.js +29 -3
  12. package/packages/datadog-instrumentations/src/express.js +38 -4
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +3 -3
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -1
  15. package/packages/datadog-instrumentations/src/helpers/register.js +3 -4
  16. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  17. package/packages/datadog-instrumentations/src/jest.js +27 -8
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  19. package/packages/datadog-instrumentations/src/mysql2.js +13 -8
  20. package/packages/datadog-instrumentations/src/next.js +7 -4
  21. package/packages/datadog-instrumentations/src/passport-http.js +2 -14
  22. package/packages/datadog-instrumentations/src/passport-local.js +2 -14
  23. package/packages/datadog-instrumentations/src/passport-utils.js +43 -19
  24. package/packages/datadog-instrumentations/src/pg.js +6 -6
  25. package/packages/datadog-instrumentations/src/playwright.js +17 -4
  26. package/packages/datadog-instrumentations/src/router.js +97 -1
  27. package/packages/datadog-instrumentations/src/sequelize.js +9 -4
  28. package/packages/datadog-instrumentations/src/url.js +4 -0
  29. package/packages/datadog-instrumentations/src/vitest.js +27 -2
  30. package/packages/datadog-plugin-avsc/src/schema_iterator.js +8 -3
  31. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +154 -0
  32. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  34. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  36. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  37. package/packages/datadog-plugin-aws-sdk/src/util.js +92 -0
  38. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  39. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
  40. package/packages/datadog-plugin-cucumber/src/index.js +39 -4
  41. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -3
  42. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  43. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  44. package/packages/datadog-plugin-jest/src/index.js +39 -4
  45. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +1 -1
  46. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +1 -1
  47. package/packages/datadog-plugin-mocha/src/index.js +36 -2
  48. package/packages/datadog-plugin-oracledb/src/index.js +1 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +34 -2
  50. package/packages/datadog-shimmer/src/shimmer.js +8 -4
  51. package/packages/dd-trace/src/appsec/addresses.js +3 -0
  52. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  53. package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
  54. package/packages/dd-trace/src/appsec/blocking.js +1 -1
  55. package/packages/dd-trace/src/appsec/channels.js +1 -0
  56. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +4 -0
  57. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +2 -2
  58. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  59. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
  60. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
  61. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +10 -3
  62. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +4 -0
  63. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +4 -0
  64. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -21
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +2 -2
  67. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +64 -3
  68. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -8
  69. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +7 -11
  71. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +2 -3
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +2 -2
  73. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +2 -2
  74. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +2 -2
  75. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
  76. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -3
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  78. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  79. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +32 -37
  80. package/packages/dd-trace/src/appsec/index.js +18 -13
  81. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +2 -2
  82. package/packages/dd-trace/src/appsec/rasp/utils.js +1 -1
  83. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
  84. package/packages/dd-trace/src/appsec/remote_config/index.js +25 -1
  85. package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
  86. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  87. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  88. package/packages/dd-trace/src/appsec/sdk/track_event.js +37 -24
  89. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -4
  90. package/packages/dd-trace/src/appsec/telemetry.js +10 -0
  91. package/packages/dd-trace/src/appsec/user_tracking.js +168 -0
  92. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  93. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -3
  94. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  95. package/packages/dd-trace/src/azure_metadata.js +4 -4
  96. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -4
  97. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +39 -3
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
  101. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  102. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -9
  103. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  104. package/packages/dd-trace/src/config.js +24 -32
  105. package/packages/dd-trace/src/constants.js +1 -0
  106. package/packages/dd-trace/src/crashtracking/crashtracker.js +3 -2
  107. package/packages/dd-trace/src/datastreams/processor.js +4 -6
  108. package/packages/dd-trace/src/datastreams/writer.js +6 -5
  109. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +80 -0
  110. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  111. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +6 -0
  112. package/packages/dd-trace/src/debugger/devtools_client/index.js +63 -8
  113. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +10 -67
  114. package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
  115. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
  116. package/packages/dd-trace/src/debugger/devtools_client/status.js +4 -4
  117. package/packages/dd-trace/src/debugger/index.js +14 -10
  118. package/packages/dd-trace/src/dogstatsd.js +2 -2
  119. package/packages/dd-trace/src/encode/0.4.js +23 -78
  120. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +0 -32
  121. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -2
  122. package/packages/dd-trace/src/encode/span-stats.js +0 -30
  123. package/packages/dd-trace/src/exporters/agent/writer.js +3 -3
  124. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  125. package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -1
  126. package/packages/dd-trace/src/flare/index.js +1 -1
  127. package/packages/dd-trace/src/guardrails/index.js +64 -0
  128. package/packages/dd-trace/src/guardrails/log.js +32 -0
  129. package/packages/dd-trace/src/guardrails/telemetry.js +78 -0
  130. package/packages/dd-trace/src/guardrails/util.js +10 -0
  131. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  132. package/packages/dd-trace/src/llmobs/storage.js +2 -3
  133. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  134. package/packages/dd-trace/src/{encode → msgpack}/chunk.js +8 -5
  135. package/packages/dd-trace/src/msgpack/encoder.js +309 -0
  136. package/packages/dd-trace/src/msgpack/index.js +6 -0
  137. package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
  138. package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -9
  139. package/packages/dd-trace/src/opentracing/span.js +1 -1
  140. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  141. package/packages/dd-trace/src/plugin_manager.js +4 -2
  142. package/packages/dd-trace/src/plugins/ci_plugin.js +47 -4
  143. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  144. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  145. package/packages/dd-trace/src/plugins/util/git.js +7 -7
  146. package/packages/dd-trace/src/plugins/util/test.js +36 -3
  147. package/packages/dd-trace/src/plugins/util/web.js +2 -2
  148. package/packages/dd-trace/src/profiling/config.js +3 -0
  149. package/packages/dd-trace/src/profiling/exporters/agent.js +9 -68
  150. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +76 -0
  151. package/packages/dd-trace/src/profiling/exporters/file.js +8 -4
  152. package/packages/dd-trace/src/profiling/profiler.js +62 -10
  153. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +22 -12
  154. package/packages/dd-trace/src/profiling/profilers/events.js +47 -8
  155. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -17
  156. package/packages/dd-trace/src/profiling/webspan-utils.js +23 -0
  157. package/packages/dd-trace/src/proxy.js +7 -2
  158. package/packages/dd-trace/src/runtime_metrics.js +107 -4
  159. package/packages/dd-trace/src/serverless.js +1 -1
  160. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +1 -1
  161. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +1 -1
  162. package/packages/dd-trace/src/span_processor.js +10 -10
  163. package/packages/dd-trace/src/tagger.js +1 -1
  164. package/packages/dd-trace/src/telemetry/index.js +1 -0
  165. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  166. package/packages/dd-trace/src/telemetry/logs/log-collector.js +10 -2
  167. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  168. package/packages/dd-trace/src/util.js +5 -16
  169. package/packages/datadog-instrumentations/src/qs.js +0 -24
  170. package/packages/dd-trace/src/appsec/iast/iast-log.js +0 -86
  171. package/packages/dd-trace/src/appsec/passport.js +0 -110
  172. package/packages/dd-trace/src/telemetry/init-telemetry.js +0 -75
@@ -37,7 +37,7 @@ class LangChainLLMHandler extends LangChainLanguageModelHandler {
37
37
 
38
38
  this.extractTokenMetrics(ctx.currentStore?.span, result)
39
39
 
40
- for (const completionIdx in result.generations) {
40
+ for (const completionIdx in result?.generations) {
41
41
  const completion = result.generations[completionIdx]
42
42
  if (this.isPromptCompletionSampled()) {
43
43
  tags[`langchain.response.completions.${completionIdx}.text`] = this.normalize(completion[0].text) || ''
@@ -30,7 +30,12 @@ const {
30
30
  TEST_SUITE,
31
31
  MOCHA_IS_PARALLEL,
32
32
  TEST_IS_RUM_ACTIVE,
33
- TEST_BROWSER_DRIVER
33
+ TEST_BROWSER_DRIVER,
34
+ TEST_NAME,
35
+ DI_ERROR_DEBUG_INFO_CAPTURED,
36
+ DI_DEBUG_ERROR_SNAPSHOT_ID,
37
+ DI_DEBUG_ERROR_FILE,
38
+ DI_DEBUG_ERROR_LINE
34
39
  } = require('../../dd-trace/src/plugins/util/test')
35
40
  const { COMPONENT } = require('../../dd-trace/src/constants')
36
41
  const {
@@ -47,6 +52,8 @@ const {
47
52
  const id = require('../../dd-trace/src/id')
48
53
  const log = require('../../dd-trace/src/log')
49
54
 
55
+ const debuggerParameterPerTest = new Map()
56
+
50
57
  function getTestSuiteLevelVisibilityTags (testSuiteSpan) {
51
58
  const testSuiteSpanContext = testSuiteSpan.context()
52
59
  const suiteTags = {
@@ -185,6 +192,28 @@ class MochaPlugin extends CiPlugin {
185
192
  const store = storage.getStore()
186
193
  const span = this.startTestSpan(testInfo)
187
194
 
195
+ const { testName } = testInfo
196
+
197
+ const debuggerParameters = debuggerParameterPerTest.get(testName)
198
+
199
+ if (debuggerParameters) {
200
+ const spanContext = span.context()
201
+
202
+ // TODO: handle race conditions with this.retriedTestIds
203
+ this.retriedTestIds = {
204
+ spanId: spanContext.toSpanId(),
205
+ traceId: spanContext.toTraceId()
206
+ }
207
+ const { snapshotId, file, line } = debuggerParameters
208
+
209
+ // TODO: should these be added on test:end if and only if the probe is hit?
210
+ // Sync issues: `hitProbePromise` might be resolved after the test ends
211
+ span.setTag(DI_ERROR_DEBUG_INFO_CAPTURED, 'true')
212
+ span.setTag(DI_DEBUG_ERROR_SNAPSHOT_ID, snapshotId)
213
+ span.setTag(DI_DEBUG_ERROR_FILE, file)
214
+ span.setTag(DI_DEBUG_ERROR_LINE, line)
215
+ }
216
+
188
217
  this.enter(span, store)
189
218
  })
190
219
 
@@ -242,7 +271,7 @@ class MochaPlugin extends CiPlugin {
242
271
  }
243
272
  })
244
273
 
245
- this.addSub('ci:mocha:test:retry', ({ isFirstAttempt, err }) => {
274
+ this.addSub('ci:mocha:test:retry', ({ isFirstAttempt, willBeRetried, err }) => {
246
275
  const store = storage.getStore()
247
276
  const span = store?.span
248
277
  if (span) {
@@ -265,6 +294,11 @@ class MochaPlugin extends CiPlugin {
265
294
  browserDriver: spanTags[TEST_BROWSER_DRIVER]
266
295
  }
267
296
  )
297
+ if (willBeRetried && this.di && this.libraryConfig?.isDiEnabled) {
298
+ const testName = span.context()._tags[TEST_NAME]
299
+ const debuggerParameters = this.addDiProbe(err)
300
+ debuggerParameterPerTest.set(testName, debuggerParameters)
301
+ }
268
302
 
269
303
  span.finish()
270
304
  finishAllTraceSpans(span)
@@ -33,7 +33,7 @@ function getUrl (connectString) {
33
33
  try {
34
34
  return new URL(`http://${connectString}`)
35
35
  } catch (e) {
36
- log.error(e)
36
+ log.error('Invalid oracle connection string', e)
37
37
  return {}
38
38
  }
39
39
  }
@@ -17,7 +17,12 @@ const {
17
17
  TEST_SOURCE_START,
18
18
  TEST_IS_NEW,
19
19
  TEST_EARLY_FLAKE_ENABLED,
20
- TEST_EARLY_FLAKE_ABORT_REASON
20
+ TEST_EARLY_FLAKE_ABORT_REASON,
21
+ TEST_NAME,
22
+ DI_ERROR_DEBUG_INFO_CAPTURED,
23
+ DI_DEBUG_ERROR_SNAPSHOT_ID,
24
+ DI_DEBUG_ERROR_FILE,
25
+ DI_DEBUG_ERROR_LINE
21
26
  } = require('../../dd-trace/src/plugins/util/test')
22
27
  const { COMPONENT } = require('../../dd-trace/src/constants')
23
28
  const {
@@ -31,6 +36,8 @@ const {
31
36
  // This is because there's some loss of resolution.
32
37
  const MILLISECONDS_TO_SUBTRACT_FROM_FAILED_TEST_DURATION = 5
33
38
 
39
+ const debuggerParameterPerTest = new Map()
40
+
34
41
  class VitestPlugin extends CiPlugin {
35
42
  static get id () {
36
43
  return 'vitest'
@@ -81,6 +88,26 @@ class VitestPlugin extends CiPlugin {
81
88
  extraTags
82
89
  )
83
90
 
91
+ const debuggerParameters = debuggerParameterPerTest.get(testName)
92
+
93
+ if (debuggerParameters) {
94
+ const spanContext = span.context()
95
+
96
+ // TODO: handle race conditions with this.retriedTestIds
97
+ this.retriedTestIds = {
98
+ spanId: spanContext.toSpanId(),
99
+ traceId: spanContext.toTraceId()
100
+ }
101
+ const { snapshotId, file, line } = debuggerParameters
102
+
103
+ // TODO: should these be added on test:end if and only if the probe is hit?
104
+ // Sync issues: `hitProbePromise` might be resolved after the test ends
105
+ span.setTag(DI_ERROR_DEBUG_INFO_CAPTURED, 'true')
106
+ span.setTag(DI_DEBUG_ERROR_SNAPSHOT_ID, snapshotId)
107
+ span.setTag(DI_DEBUG_ERROR_FILE, file)
108
+ span.setTag(DI_DEBUG_ERROR_LINE, line)
109
+ }
110
+
84
111
  this.enter(span, store)
85
112
  })
86
113
 
@@ -110,11 +137,16 @@ class VitestPlugin extends CiPlugin {
110
137
  }
111
138
  })
112
139
 
113
- this.addSub('ci:vitest:test:error', ({ duration, error }) => {
140
+ this.addSub('ci:vitest:test:error', ({ duration, error, willBeRetried, probe, isDiEnabled }) => {
114
141
  const store = storage.getStore()
115
142
  const span = store?.span
116
143
 
117
144
  if (span) {
145
+ if (willBeRetried && this.di && isDiEnabled) {
146
+ const testName = span.context()._tags[TEST_NAME]
147
+ const debuggerParameters = this.addDiProbe(error, probe)
148
+ debuggerParameterPerTest.set(testName, debuggerParameters)
149
+ }
118
150
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'test', {
119
151
  hasCodeowners: !!span.context()._tags[TEST_CODE_OWNERS]
120
152
  })
@@ -6,8 +6,12 @@ const log = require('../../dd-trace/src/log')
6
6
  const unwrappers = new WeakMap()
7
7
 
8
8
  function copyProperties (original, wrapped) {
9
- Object.setPrototypeOf(wrapped, original)
10
-
9
+ // TODO getPrototypeOf is not fast. Should we instead do this in specific
10
+ // instrumentations where needed?
11
+ const proto = Object.getPrototypeOf(original)
12
+ if (proto !== Function.prototype) {
13
+ Object.setPrototypeOf(wrapped, proto)
14
+ }
11
15
  const props = Object.getOwnPropertyDescriptors(original)
12
16
  const keys = Reflect.ownKeys(props)
13
17
 
@@ -136,7 +140,7 @@ function wrapMethod (target, name, wrapper, noAssert) {
136
140
  if (callState.completed) {
137
141
  // error was thrown after original function returned/resolved, so
138
142
  // it was us. log it.
139
- log.error(e)
143
+ log.error('Shimmer error was thrown after original function returned/resolved', e)
140
144
  // original ran and returned something. return it.
141
145
  return callState.retVal
142
146
  }
@@ -144,7 +148,7 @@ function wrapMethod (target, name, wrapper, noAssert) {
144
148
  if (!callState.called) {
145
149
  // error was thrown before original function was called, so
146
150
  // it was us. log it.
147
- log.error(e)
151
+ log.error('Shimmer error was thrown before original function was called', e)
148
152
  // original never ran. call it unwrapped.
149
153
  return original.apply(this, args)
150
154
  }
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ // TODO: reorder all this, it's a mess
3
4
  module.exports = {
4
5
  HTTP_INCOMING_BODY: 'server.request.body',
5
6
  HTTP_INCOMING_QUERY: 'server.request.query',
@@ -20,6 +21,8 @@ module.exports = {
20
21
  HTTP_CLIENT_IP: 'http.client_ip',
21
22
 
22
23
  USER_ID: 'usr.id',
24
+ USER_LOGIN: 'usr.login',
25
+
23
26
  WAF_CONTEXT_PROCESSOR: 'waf.context.processor',
24
27
 
25
28
  HTTP_OUTGOING_URL: 'server.io.net.url',
@@ -64,7 +64,7 @@ function computeKey (req, res) {
64
64
  const status = res.statusCode
65
65
 
66
66
  if (!method || !status) {
67
- log.warn('Unsupported groupkey for API security')
67
+ log.warn('[ASM] Unsupported groupkey for API security')
68
68
  return null
69
69
  }
70
70
  return method + route + status
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-len */
1
+ /* eslint-disable @stylistic/js/max-len */
2
2
  'use strict'
3
3
 
4
4
  const html = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>You've been blocked</title><style>a,body,div,html,span{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1;flex-direction:column}p{display:block}main{text-align:center;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;flex-direction:column}p{font-size:18px;line-height:normal;color:#646464;font-family:sans-serif;font-weight:400}a{color:#4842b7}footer{width:100%;text-align:center}footer p{font-size:16px}</style></head><body><main><p>Sorry, you cannot access this page. Please contact the customer service team.</p></main><footer><p>Security provided by <a href="https://www.datadoghq.com/product/security-platform/application-security-monitoring/" target="_blank">Datadog</a></p></footer></body></html>`
@@ -101,7 +101,7 @@ function getBlockingData (req, specificType, actionParameters) {
101
101
 
102
102
  function block (req, res, rootSpan, abortController, actionParameters = defaultBlockingActionParameters) {
103
103
  if (res.headersSent) {
104
- log.warn('Cannot send blocking response when headers have already been sent')
104
+ log.warn('[ASM] Cannot send blocking response when headers have already been sent')
105
105
  return
106
106
  }
107
107
 
@@ -19,6 +19,7 @@ module.exports = {
19
19
  nextBodyParsed: dc.channel('apm:next:body-parsed'),
20
20
  nextQueryParsed: dc.channel('apm:next:query-parsed'),
21
21
  expressProcessParams: dc.channel('datadog:express:process_params:start'),
22
+ routerParam: dc.channel('datadog:router:param:start'),
22
23
  responseBody: dc.channel('datadog:express:response:json:start'),
23
24
  responseWriteHead: dc.channel('apm:http:server:response:writeHead:start'),
24
25
  httpClientRequestStart: dc.channel('apm:http:client:request:start'),
@@ -11,6 +11,10 @@ class CodeInjectionAnalyzer extends InjectionAnalyzer {
11
11
  onConfigure () {
12
12
  this.addSub('datadog:eval:call', ({ script }) => this.analyze(script))
13
13
  }
14
+
15
+ _areRangesVulnerable () {
16
+ return true
17
+ }
14
18
  }
15
19
 
16
20
  module.exports = new CodeInjectionAnalyzer()
@@ -2,7 +2,7 @@
2
2
 
3
3
  const Analyzer = require('./vulnerability-analyzer')
4
4
  const { getNodeModulesPaths } = require('../path-line')
5
- const iastLog = require('../iast-log')
5
+ const log = require('../../../log')
6
6
 
7
7
  const EXCLUDED_PATHS = getNodeModulesPaths('express/lib/response.js')
8
8
 
@@ -16,7 +16,7 @@ class CookieAnalyzer extends Analyzer {
16
16
  try {
17
17
  this.cookieFilterRegExp = new RegExp(config.iast.cookieFilterPattern)
18
18
  } catch {
19
- iastLog.error('Invalid regex in cookieFilterPattern')
19
+ log.error('[ASM] Invalid regex in cookieFilterPattern')
20
20
  this.cookieFilterRegExp = /.{32,}/
21
21
  }
22
22
 
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-len */
1
+ /* eslint-disable @stylistic/js/max-len */
2
2
  'use strict'
3
3
 
4
4
  const { NameAndValue } = require('./hardcoded-rule-type')
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-len */
1
+ /* eslint-disable @stylistic/js/max-len */
2
2
  'use strict'
3
3
 
4
4
  const { ValueOnly, NameAndValue } = require('./hardcoded-rule-type')
@@ -1,4 +1,4 @@
1
- /* eslint-disable max-len */
1
+ /* eslint-disable @stylistic/js/max-len */
2
2
  'use strict'
3
3
 
4
4
  const { ValueOnly, NameAndValue } = require('./hardcoded-rule-type')
@@ -1,12 +1,15 @@
1
1
  'use strict'
2
2
  const Analyzer = require('./vulnerability-analyzer')
3
- const { isTainted, getRanges } = require('../taint-tracking/operations')
3
+ const { getRanges } = require('../taint-tracking/operations')
4
+ const { SQL_ROW_VALUE } = require('../taint-tracking/source-types')
4
5
 
5
6
  class InjectionAnalyzer extends Analyzer {
6
7
  _isVulnerable (value, iastContext) {
7
- if (value) {
8
- return isTainted(iastContext, value)
8
+ const ranges = value && getRanges(iastContext, value)
9
+ if (ranges?.length > 0) {
10
+ return this._areRangesVulnerable(ranges)
9
11
  }
12
+
10
13
  return false
11
14
  }
12
15
 
@@ -14,6 +17,10 @@ class InjectionAnalyzer extends Analyzer {
14
17
  const ranges = getRanges(iastContext, value)
15
18
  return { value, ranges }
16
19
  }
20
+
21
+ _areRangesVulnerable (ranges) {
22
+ return ranges?.some(range => range.iinfo.type !== SQL_ROW_VALUE)
23
+ }
17
24
  }
18
25
 
19
26
  module.exports = InjectionAnalyzer
@@ -82,6 +82,10 @@ class SqlInjectionAnalyzer extends InjectionAnalyzer {
82
82
  return knexDialect.toUpperCase()
83
83
  }
84
84
  }
85
+
86
+ _areRangesVulnerable () {
87
+ return true
88
+ }
85
89
  }
86
90
 
87
91
  module.exports = new SqlInjectionAnalyzer()
@@ -13,6 +13,10 @@ class TemplateInjectionAnalyzer extends InjectionAnalyzer {
13
13
  this.addSub('datadog:handlebars:register-partial:start', ({ partial }) => this.analyze(partial))
14
14
  this.addSub('datadog:pug:compile:start', ({ source }) => this.analyze(source))
15
15
  }
16
+
17
+ _areRangesVulnerable () {
18
+ return true
19
+ }
16
20
  }
17
21
 
18
22
  module.exports = new TemplateInjectionAnalyzer()
@@ -2,7 +2,6 @@
2
2
 
3
3
  const { channel } = require('dc-polyfill')
4
4
 
5
- const iastLog = require('./iast-log')
6
5
  const Plugin = require('../../plugins/plugin')
7
6
  const iastTelemetry = require('./telemetry')
8
7
  const { getInstrumentedMetric, getExecutedMetric, TagKey, EXECUTED_SOURCE, formatTags } =
@@ -10,6 +9,7 @@ const { getInstrumentedMetric, getExecutedMetric, TagKey, EXECUTED_SOURCE, forma
10
9
  const { storage } = require('../../../../datadog-core')
11
10
  const { getIastContext } = require('./iast-context')
12
11
  const instrumentations = require('../../../../datadog-instrumentations/src/helpers/instrumentations')
12
+ const log = require('../../log')
13
13
 
14
14
  /**
15
15
  * Used by vulnerability sources and sinks to subscribe diagnostic channel events
@@ -60,24 +60,10 @@ class IastPlugin extends Plugin {
60
60
  this.pluginSubs = []
61
61
  }
62
62
 
63
- _wrapHandler (handler) {
64
- return (message, name) => {
65
- try {
66
- handler(message, name)
67
- } catch (e) {
68
- iastLog.errorAndPublish(e)
69
- }
70
- }
71
- }
72
-
73
63
  _getTelemetryHandler (iastSub) {
74
64
  return () => {
75
- try {
76
- const iastContext = getIastContext(storage.getStore())
77
- iastSub.increaseExecuted(iastContext)
78
- } catch (e) {
79
- iastLog.errorAndPublish(e)
80
- }
65
+ const iastContext = getIastContext(storage.getStore())
66
+ iastSub.increaseExecuted(iastContext)
81
67
  }
82
68
  }
83
69
 
@@ -93,17 +79,17 @@ class IastPlugin extends Plugin {
93
79
  }
94
80
  return result
95
81
  } catch (e) {
96
- iastLog.errorAndPublish(e)
82
+ log.error('[ASM] Error executing handler or increasing metrics', e)
97
83
  }
98
84
  }
99
85
 
100
86
  addSub (iastSub, handler) {
101
87
  if (typeof iastSub === 'string') {
102
- super.addSub(iastSub, this._wrapHandler(handler))
88
+ super.addSub(iastSub, handler)
103
89
  } else {
104
90
  iastSub = this._getAndRegisterSubscription(iastSub)
105
91
  if (iastSub) {
106
- super.addSub(iastSub.channelName, this._wrapHandler(handler))
92
+ super.addSub(iastSub.channelName, handler)
107
93
 
108
94
  if (iastTelemetry.isEnabled()) {
109
95
  super.addSub(iastSub.channelName, this._getTelemetryHandler(iastSub))
@@ -112,7 +98,8 @@ class IastPlugin extends Plugin {
112
98
  }
113
99
  }
114
100
 
115
- enable () {
101
+ enable (iastConfig) {
102
+ this.iastConfig = iastConfig
116
103
  this.configure(true)
117
104
  }
118
105
 
@@ -18,10 +18,10 @@ module.exports = {
18
18
  enableTaintTracking (config, telemetryVerbosity) {
19
19
  enableRewriter(telemetryVerbosity)
20
20
  enableTaintOperations(telemetryVerbosity)
21
- taintTrackingPlugin.enable()
21
+ taintTrackingPlugin.enable(config)
22
22
 
23
- kafkaContextPlugin.enable()
24
- kafkaConsumerPlugin.enable()
23
+ kafkaContextPlugin.enable(config)
24
+ kafkaConsumerPlugin.enable(config)
25
25
 
26
26
  setMaxTransactions(config.maxConcurrentRequests)
27
27
  },
@@ -2,7 +2,7 @@
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')
5
+ const log = require('../../../log')
6
6
 
7
7
  function taintObject (iastContext, object, type) {
8
8
  let result = object
@@ -33,7 +33,7 @@ function taintObject (iastContext, object, type) {
33
33
  }
34
34
  }
35
35
  } catch (e) {
36
- iastLog.error(`Error visiting property : ${property}`).errorAndPublish(e)
36
+ log.error('[ASM] Error in taintObject when visiting property : %s', property, e)
37
37
  }
38
38
  }
39
39
  }
@@ -12,7 +12,8 @@ const {
12
12
  HTTP_REQUEST_HEADER_NAME,
13
13
  HTTP_REQUEST_PARAMETER,
14
14
  HTTP_REQUEST_PATH_PARAM,
15
- HTTP_REQUEST_URI
15
+ HTTP_REQUEST_URI,
16
+ SQL_ROW_VALUE
16
17
  } = require('./source-types')
17
18
  const { EXECUTED_SOURCE } = require('../telemetry/iast-metric')
18
19
 
@@ -26,6 +27,16 @@ class TaintTrackingPlugin extends SourceIastPlugin {
26
27
  this._taintedURLs = new WeakMap()
27
28
  }
28
29
 
30
+ configure (config) {
31
+ super.configure(config)
32
+
33
+ let rowsToTaint = this.iastConfig?.dbRowsToTaint
34
+ if (typeof rowsToTaint !== 'number') {
35
+ rowsToTaint = 1
36
+ }
37
+ this._rowsToTaint = rowsToTaint
38
+ }
39
+
29
40
  onConfigure () {
30
41
  const onRequestBody = ({ req }) => {
31
42
  const iastContext = getIastContext(storage.getStore())
@@ -46,8 +57,13 @@ class TaintTrackingPlugin extends SourceIastPlugin {
46
57
  )
47
58
 
48
59
  this.addSub(
49
- { channelName: 'datadog:qs:parse:finish', tag: HTTP_REQUEST_PARAMETER },
50
- ({ qs }) => this._taintTrackingHandler(HTTP_REQUEST_PARAMETER, qs)
60
+ { channelName: 'datadog:query:read:finish', tag: HTTP_REQUEST_PARAMETER },
61
+ ({ query }) => this._taintTrackingHandler(HTTP_REQUEST_PARAMETER, query)
62
+ )
63
+
64
+ this.addSub(
65
+ { channelName: 'datadog:express:query:finish', tag: HTTP_REQUEST_PARAMETER },
66
+ ({ query }) => this._taintTrackingHandler(HTTP_REQUEST_PARAMETER, query)
51
67
  )
52
68
 
53
69
  this.addSub(
@@ -68,6 +84,16 @@ class TaintTrackingPlugin extends SourceIastPlugin {
68
84
  ({ cookies }) => this._cookiesTaintTrackingHandler(cookies)
69
85
  )
70
86
 
87
+ this.addSub(
88
+ { channelName: 'datadog:sequelize:query:finish', tag: SQL_ROW_VALUE },
89
+ ({ result }) => this._taintDatabaseResult(result, 'sequelize')
90
+ )
91
+
92
+ this.addSub(
93
+ { channelName: 'apm:pg:query:finish', tag: SQL_ROW_VALUE },
94
+ ({ result }) => this._taintDatabaseResult(result, 'pg')
95
+ )
96
+
71
97
  this.addSub(
72
98
  { channelName: 'datadog:express:process_params:start', tag: HTTP_REQUEST_PATH_PARAM },
73
99
  ({ req }) => {
@@ -77,6 +103,15 @@ class TaintTrackingPlugin extends SourceIastPlugin {
77
103
  }
78
104
  )
79
105
 
106
+ this.addSub(
107
+ { channelName: 'datadog:router:param:start', tag: HTTP_REQUEST_PATH_PARAM },
108
+ ({ req }) => {
109
+ if (req && req.params !== null && typeof req.params === 'object') {
110
+ this._taintTrackingHandler(HTTP_REQUEST_PATH_PARAM, req, 'params')
111
+ }
112
+ }
113
+ )
114
+
80
115
  this.addSub(
81
116
  { channelName: 'apm:graphql:resolve:start', tag: HTTP_REQUEST_BODY },
82
117
  (data) => {
@@ -170,6 +205,32 @@ class TaintTrackingPlugin extends SourceIastPlugin {
170
205
  this.taintHeaders(req.headers, iastContext)
171
206
  this.taintUrl(req, iastContext)
172
207
  }
208
+
209
+ _taintDatabaseResult (result, dbOrigin, iastContext = getIastContext(storage.getStore()), name) {
210
+ if (!iastContext) return result
211
+
212
+ if (this._rowsToTaint === 0) return result
213
+
214
+ if (Array.isArray(result)) {
215
+ for (let i = 0; i < result.length && i < this._rowsToTaint; i++) {
216
+ const nextName = name ? `${name}.${i}` : '' + i
217
+ result[i] = this._taintDatabaseResult(result[i], dbOrigin, iastContext, nextName)
218
+ }
219
+ } else if (result && typeof result === 'object') {
220
+ if (dbOrigin === 'sequelize' && result.dataValues) {
221
+ result.dataValues = this._taintDatabaseResult(result.dataValues, dbOrigin, iastContext, name)
222
+ } else {
223
+ for (const key in result) {
224
+ const nextName = name ? `${name}.${key}` : key
225
+ result[key] = this._taintDatabaseResult(result[key], dbOrigin, iastContext, nextName)
226
+ }
227
+ }
228
+ } else if (typeof result === 'string') {
229
+ result = newTaintedString(iastContext, result, name, SQL_ROW_VALUE)
230
+ }
231
+
232
+ return result
233
+ }
173
234
  }
174
235
 
175
236
  module.exports = new TaintTrackingPlugin()
@@ -2,12 +2,12 @@
2
2
 
3
3
  const Module = require('module')
4
4
  const shimmer = require('../../../../../datadog-shimmer')
5
- const iastLog = require('../iast-log')
6
5
  const { isPrivateModule, isNotLibraryFile } = require('./filter')
7
6
  const { csiMethods } = require('./csi-methods')
8
7
  const { getName } = require('../telemetry/verbosity')
9
8
  const { getRewriteFunction } = require('./rewriter-telemetry')
10
9
  const dc = require('dc-polyfill')
10
+ const log = require('../../../log')
11
11
 
12
12
  const hardcodedSecretCh = dc.channel('datadog:secrets:result')
13
13
  let rewriter
@@ -60,8 +60,7 @@ function getRewriter (telemetryVerbosity) {
60
60
  chainSourceMap
61
61
  })
62
62
  } catch (e) {
63
- iastLog.error('Unable to initialize TaintTracking Rewriter')
64
- .errorAndPublish(e)
63
+ log.error('[ASM] Unable to initialize TaintTracking Rewriter', e)
65
64
  }
66
65
  }
67
66
  return rewriter
@@ -99,8 +98,7 @@ function getCompileMethodFn (compileMethod) {
99
98
  }
100
99
  }
101
100
  } catch (e) {
102
- iastLog.error(`Error rewriting ${filename}`)
103
- .errorAndPublish(e)
101
+ log.error('[ASM] Error rewriting file %s', filename, e)
104
102
  }
105
103
  return compileMethod.apply(this, [content, filename])
106
104
  }
@@ -117,8 +115,7 @@ function enableRewriter (telemetryVerbosity) {
117
115
  shimmer.wrap(Module.prototype, '_compile', compileMethod => getCompileMethodFn(compileMethod))
118
116
  }
119
117
  } catch (e) {
120
- iastLog.error('Error enabling TaintTracking Rewriter')
121
- .errorAndPublish(e)
118
+ log.error('[ASM] Error enabling TaintTracking Rewriter', e)
122
119
  }
123
120
  }
124
121
 
@@ -132,7 +129,7 @@ function disableRewriter () {
132
129
 
133
130
  Error.prepareStackTrace = originalPrepareStackTrace
134
131
  } catch (e) {
135
- iastLog.warn(e)
132
+ log.warn('[ASM] Error disabling TaintTracking rewriter', e)
136
133
  }
137
134
  }
138
135
 
@@ -11,5 +11,6 @@ module.exports = {
11
11
  HTTP_REQUEST_PATH_PARAM: 'http.request.path.parameter',
12
12
  HTTP_REQUEST_URI: 'http.request.uri',
13
13
  KAFKA_MESSAGE_KEY: 'kafka.message.key',
14
- KAFKA_MESSAGE_VALUE: 'kafka.message.value'
14
+ KAFKA_MESSAGE_VALUE: 'kafka.message.value',
15
+ SQL_ROW_VALUE: 'sql.row.value'
15
16
  }