dd-trace 2.28.0 → 2.30.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 (180) hide show
  1. package/LICENSE-3rdparty.csv +2 -2
  2. package/README.md +53 -0
  3. package/ci/init.js +9 -1
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +6 -2
  7. package/package.json +24 -19
  8. package/packages/datadog-esbuild/index.js +104 -0
  9. package/packages/datadog-instrumentations/src/cucumber.js +80 -3
  10. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +100 -27
  11. package/packages/datadog-instrumentations/src/helpers/hook.js +13 -3
  12. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  13. package/packages/datadog-instrumentations/src/helpers/instrument.js +6 -0
  14. package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
  15. package/packages/datadog-instrumentations/src/jest.js +35 -3
  16. package/packages/datadog-instrumentations/src/mariadb.js +130 -11
  17. package/packages/datadog-instrumentations/src/mocha.js +30 -6
  18. package/packages/datadog-instrumentations/src/mongodb-core.js +8 -2
  19. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  20. package/packages/datadog-instrumentations/src/next.js +32 -4
  21. package/packages/datadog-instrumentations/src/pg.js +16 -11
  22. package/packages/datadog-instrumentations/src/playwright.js +2 -2
  23. package/packages/datadog-plugin-amqp10/src/consumer.js +1 -1
  24. package/packages/datadog-plugin-amqp10/src/index.js +1 -1
  25. package/packages/datadog-plugin-amqp10/src/producer.js +3 -2
  26. package/packages/datadog-plugin-amqplib/src/client.js +3 -2
  27. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  28. package/packages/datadog-plugin-amqplib/src/index.js +1 -1
  29. package/packages/datadog-plugin-amqplib/src/producer.js +3 -2
  30. package/packages/datadog-plugin-aws-sdk/src/base.js +7 -2
  31. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  32. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -0
  33. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +2 -0
  34. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -0
  35. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -0
  36. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +2 -0
  37. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -0
  38. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -0
  39. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
  40. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -0
  41. package/packages/datadog-plugin-bunyan/src/index.js +1 -1
  42. package/packages/datadog-plugin-cassandra-driver/src/index.js +3 -2
  43. package/packages/datadog-plugin-connect/src/index.js +1 -1
  44. package/packages/datadog-plugin-couchbase/src/index.js +1 -1
  45. package/packages/datadog-plugin-cucumber/src/index.js +33 -6
  46. package/packages/datadog-plugin-cypress/src/index.js +1 -1
  47. package/packages/datadog-plugin-cypress/src/plugin.js +40 -33
  48. package/packages/datadog-plugin-dns/src/index.js +1 -1
  49. package/packages/datadog-plugin-dns/src/lookup.js +1 -1
  50. package/packages/datadog-plugin-dns/src/lookup_service.js +1 -1
  51. package/packages/datadog-plugin-dns/src/resolve.js +1 -1
  52. package/packages/datadog-plugin-dns/src/reverse.js +1 -1
  53. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  54. package/packages/datadog-plugin-express/src/index.js +1 -1
  55. package/packages/datadog-plugin-fastify/src/index.js +1 -1
  56. package/packages/datadog-plugin-find-my-way/src/index.js +1 -1
  57. package/packages/datadog-plugin-fs/src/index.js +1 -1
  58. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +5 -5
  59. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  60. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -1
  61. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +7 -6
  62. package/packages/datadog-plugin-graphql/src/execute.js +1 -1
  63. package/packages/datadog-plugin-graphql/src/index.js +1 -1
  64. package/packages/datadog-plugin-graphql/src/parse.js +1 -1
  65. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  66. package/packages/datadog-plugin-graphql/src/validate.js +1 -1
  67. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  68. package/packages/datadog-plugin-grpc/src/index.js +1 -1
  69. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  70. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  71. package/packages/datadog-plugin-http/src/client.js +2 -2
  72. package/packages/datadog-plugin-http/src/index.js +1 -1
  73. package/packages/datadog-plugin-http/src/server.js +2 -2
  74. package/packages/datadog-plugin-http2/src/client.js +4 -3
  75. package/packages/datadog-plugin-http2/src/index.js +1 -1
  76. package/packages/datadog-plugin-http2/src/server.js +2 -2
  77. package/packages/datadog-plugin-ioredis/src/index.js +1 -1
  78. package/packages/datadog-plugin-jest/src/index.js +53 -19
  79. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -1
  80. package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
  81. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
  82. package/packages/datadog-plugin-koa/src/index.js +1 -1
  83. package/packages/datadog-plugin-mariadb/src/index.js +18 -1
  84. package/packages/datadog-plugin-memcached/src/index.js +3 -2
  85. package/packages/datadog-plugin-microgateway-core/src/index.js +1 -1
  86. package/packages/datadog-plugin-mocha/src/index.js +13 -9
  87. package/packages/datadog-plugin-moleculer/src/client.js +1 -1
  88. package/packages/datadog-plugin-moleculer/src/index.js +1 -1
  89. package/packages/datadog-plugin-moleculer/src/server.js +1 -1
  90. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
  91. package/packages/datadog-plugin-mysql/src/index.js +3 -2
  92. package/packages/datadog-plugin-mysql2/src/index.js +1 -1
  93. package/packages/datadog-plugin-net/src/index.js +9 -75
  94. package/packages/datadog-plugin-net/src/ipc.js +1 -1
  95. package/packages/datadog-plugin-net/src/tcp.js +3 -2
  96. package/packages/datadog-plugin-next/src/index.js +3 -3
  97. package/packages/datadog-plugin-opensearch/src/index.js +1 -1
  98. package/packages/datadog-plugin-oracledb/src/index.js +3 -2
  99. package/packages/datadog-plugin-paperplane/src/index.js +1 -1
  100. package/packages/datadog-plugin-paperplane/src/logger.js +1 -1
  101. package/packages/datadog-plugin-paperplane/src/server.js +1 -1
  102. package/packages/datadog-plugin-pg/src/index.js +3 -2
  103. package/packages/datadog-plugin-pino/src/index.js +1 -1
  104. package/packages/datadog-plugin-playwright/src/index.js +5 -4
  105. package/packages/datadog-plugin-redis/src/index.js +3 -2
  106. package/packages/datadog-plugin-restify/src/index.js +1 -1
  107. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  108. package/packages/datadog-plugin-rhea/src/index.js +1 -1
  109. package/packages/datadog-plugin-rhea/src/producer.js +3 -2
  110. package/packages/datadog-plugin-router/src/index.js +8 -8
  111. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  112. package/packages/datadog-plugin-tedious/src/index.js +3 -2
  113. package/packages/datadog-plugin-web/src/index.js +1 -1
  114. package/packages/datadog-plugin-winston/src/index.js +1 -1
  115. package/packages/dd-trace/src/appsec/{templates/blocked.html → blocked_templates.js} +19 -1
  116. package/packages/dd-trace/src/appsec/blocking.js +9 -24
  117. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +2 -1
  118. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
  119. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +12 -0
  120. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  121. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +11 -5
  122. package/packages/dd-trace/src/appsec/iast/iast-log.js +111 -0
  123. package/packages/dd-trace/src/appsec/iast/index.js +8 -4
  124. package/packages/dd-trace/src/appsec/iast/path-line.js +3 -6
  125. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +11 -2
  126. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +11 -0
  127. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +2 -0
  128. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -0
  129. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -3
  130. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +5 -3
  131. package/packages/dd-trace/src/appsec/iast/telemetry/log_collector.js +96 -0
  132. package/packages/dd-trace/src/appsec/iast/telemetry/logs.js +87 -0
  133. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +27 -2
  134. package/packages/dd-trace/src/appsec/index.js +4 -18
  135. package/packages/dd-trace/src/appsec/recommended.json +43 -14
  136. package/packages/dd-trace/src/appsec/remote_config/index.js +1 -1
  137. package/packages/dd-trace/src/appsec/sdk/index.js +2 -2
  138. package/packages/dd-trace/src/ci-visibility/encode/json-encoder.js +27 -0
  139. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -9
  140. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -7
  141. package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/index.js +33 -0
  142. package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/writer.js +37 -0
  143. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +8 -2
  144. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +8 -2
  145. package/packages/dd-trace/src/config.js +44 -22
  146. package/packages/dd-trace/src/constants.js +2 -1
  147. package/packages/dd-trace/src/datastreams/encoding.js +80 -0
  148. package/packages/dd-trace/src/dcitm.js +51 -0
  149. package/packages/dd-trace/src/exporter.js +7 -9
  150. package/packages/dd-trace/src/exporters/common/agents.js +42 -0
  151. package/packages/dd-trace/src/exporters/common/docker.js +4 -1
  152. package/packages/dd-trace/src/exporters/common/request.js +1 -4
  153. package/packages/dd-trace/src/lambda/handler.js +14 -6
  154. package/packages/dd-trace/src/opentracing/propagation/log.js +23 -7
  155. package/packages/dd-trace/src/opentracing/propagation/text_map.js +28 -2
  156. package/packages/dd-trace/src/opentracing/span.js +19 -3
  157. package/packages/dd-trace/src/opentracing/span_context.js +3 -1
  158. package/packages/dd-trace/src/opentracing/tracer.js +3 -1
  159. package/packages/dd-trace/src/plugin_manager.js +7 -7
  160. package/packages/dd-trace/src/plugins/ci_plugin.js +16 -16
  161. package/packages/dd-trace/src/plugins/index.js +1 -0
  162. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  163. package/packages/dd-trace/src/plugins/outgoing.js +2 -1
  164. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  165. package/packages/dd-trace/src/plugins/util/ci.js +12 -0
  166. package/packages/dd-trace/src/plugins/util/ip_extractor.js +23 -27
  167. package/packages/dd-trace/src/plugins/util/test.js +26 -7
  168. package/packages/dd-trace/src/profiling/config.js +87 -20
  169. package/packages/dd-trace/src/profiling/constants.js +16 -0
  170. package/packages/dd-trace/src/profiling/exporter_cli.js +62 -0
  171. package/packages/dd-trace/src/profiling/exporters/agent.js +2 -1
  172. package/packages/dd-trace/src/profiling/profiler.js +21 -8
  173. package/packages/dd-trace/src/profiling/profilers/space.js +21 -1
  174. package/packages/dd-trace/src/span_sampler.js +3 -2
  175. package/packages/dd-trace/src/telemetry/index.js +16 -2
  176. package/packages/dd-trace/src/util.js +10 -1
  177. package/scripts/install_plugin_modules.js +5 -1
  178. package/packages/dd-trace/src/appsec/templates/blocked.json +0 -8
  179. package/scripts/junit_report.js +0 -25
  180. package/scripts/tdd.js +0 -34
@@ -1,4 +1,4 @@
1
- const { sendVulnerabilities, setTracer } = require('./vulnerability-reporter')
1
+ const vulnerabilityReporter = require('./vulnerability-reporter')
2
2
  const { enableAllAnalyzers, disableAllAnalyzers } = require('./analyzers')
3
3
  const web = require('../../plugins/util/web')
4
4
  const { storage } = require('../../../../datadog-core')
@@ -7,6 +7,7 @@ const dc = require('diagnostics_channel')
7
7
  const iastContextFunctions = require('./iast-context')
8
8
  const { enableTaintTracking, disableTaintTracking, createTransaction, removeTransaction } = require('./taint-tracking')
9
9
 
10
+ const telemetryLogs = require('./telemetry/logs')
10
11
  const IAST_ENABLED_TAG_KEY = '_dd.iast.enabled'
11
12
 
12
13
  // TODO Change to `apm:http:server:request:[start|close]` when the subscription
@@ -16,12 +17,13 @@ const requestClose = dc.channel('dd-trace:incomingHttpRequestEnd')
16
17
 
17
18
  function enable (config, _tracer) {
18
19
  enableAllAnalyzers()
19
- enableTaintTracking()
20
+ enableTaintTracking(config.iast)
20
21
  requestStart.subscribe(onIncomingHttpRequestStart)
21
22
  requestClose.subscribe(onIncomingHttpRequestEnd)
22
23
  overheadController.configure(config.iast)
23
24
  overheadController.startGlobalContext()
24
- setTracer(_tracer)
25
+ vulnerabilityReporter.start(config, _tracer)
26
+ telemetryLogs.start()
25
27
  }
26
28
 
27
29
  function disable () {
@@ -30,6 +32,8 @@ function disable () {
30
32
  overheadController.finishGlobalContext()
31
33
  if (requestStart.hasSubscribers) requestStart.unsubscribe(onIncomingHttpRequestStart)
32
34
  if (requestClose.hasSubscribers) requestClose.unsubscribe(onIncomingHttpRequestEnd)
35
+ vulnerabilityReporter.stop()
36
+ telemetryLogs.stop()
33
37
  }
34
38
 
35
39
  function onIncomingHttpRequestStart (data) {
@@ -63,7 +67,7 @@ function onIncomingHttpRequestEnd (data) {
63
67
  if (iastContext && iastContext.rootSpan) {
64
68
  const vulnerabilities = iastContext.vulnerabilities
65
69
  const rootSpan = iastContext.rootSpan
66
- sendVulnerabilities(vulnerabilities, rootSpan)
70
+ vulnerabilityReporter.sendVulnerabilities(vulnerabilities, rootSpan)
67
71
  removeTransaction(iastContext)
68
72
  }
69
73
  // TODO web.getContext(data.req) is required when the request is aborted
@@ -1,5 +1,8 @@
1
+ 'use strict'
2
+
1
3
  const path = require('path')
2
4
  const process = require('process')
5
+ const { calculateDDBasePath } = require('../../util')
3
6
  const pathLine = {
4
7
  getFirstNonDDPathAndLine,
5
8
  getFirstNonDDPathAndLineFromCallsites, // Exported only for test purposes
@@ -19,12 +22,6 @@ const EXCLUDED_PATH_PREFIXES = [
19
22
  'async_hooks'
20
23
  ]
21
24
 
22
- function calculateDDBasePath (dirname) {
23
- const dirSteps = dirname.split(path.sep)
24
- const packagesIndex = dirSteps.lastIndexOf('packages')
25
- return dirSteps.slice(0, packagesIndex).join(path.sep) + path.sep
26
- }
27
-
28
25
  function getCallSiteInfo () {
29
26
  const previousPrepareStackTrace = Error.prepareStackTrace
30
27
  const previousStackTraceLimit = Error.stackTraceLimit
@@ -1,18 +1,27 @@
1
+ 'use strict'
2
+
1
3
  const { enableRewriter, disableRewriter } = require('./rewriter')
2
- const { createTransaction, removeTransaction, enableTaintOperations, disableTaintOperations } = require('./operations')
4
+ const { createTransaction,
5
+ removeTransaction,
6
+ setMaxTransactions,
7
+ enableTaintOperations,
8
+ disableTaintOperations } = require('./operations')
9
+
3
10
  const taintTrackingPlugin = require('./plugin')
4
11
 
5
12
  module.exports = {
6
- enableTaintTracking () {
13
+ enableTaintTracking (config) {
7
14
  enableRewriter()
8
15
  enableTaintOperations()
9
16
  taintTrackingPlugin.enable()
17
+ setMaxTransactions(config.maxConcurrentRequests)
10
18
  },
11
19
  disableTaintTracking () {
12
20
  disableRewriter()
13
21
  disableTaintOperations()
14
22
  taintTrackingPlugin.disable()
15
23
  },
24
+ setMaxTransactions: setMaxTransactions,
16
25
  createTransaction: createTransaction,
17
26
  removeTransaction: removeTransaction
18
27
  }
@@ -1,3 +1,5 @@
1
+ 'use strict'
2
+
1
3
  const TaintedUtils = require('@datadog/native-iast-taint-tracking')
2
4
  const { IAST_TRANSACTION_ID } = require('../iast-context')
3
5
  const { TaintTracking, TaintTrackingDummy } = require('./taint-tracking-impl')
@@ -85,6 +87,14 @@ function disableTaintOperations () {
85
87
  global._ddiast = TaintTrackingDummy
86
88
  }
87
89
 
90
+ function setMaxTransactions (transactions) {
91
+ if (!transactions) {
92
+ return
93
+ }
94
+
95
+ TaintedUtils.setMaxTransactions(transactions)
96
+ }
97
+
88
98
  module.exports = {
89
99
  createTransaction,
90
100
  removeTransaction,
@@ -94,5 +104,6 @@ module.exports = {
94
104
  getRanges,
95
105
  enableTaintOperations,
96
106
  disableTaintOperations,
107
+ setMaxTransactions,
97
108
  IAST_TRANSACTION_ID
98
109
  }
@@ -1,3 +1,5 @@
1
+ 'use strict'
2
+
1
3
  module.exports = {
2
4
  HTTP_REQUEST_BODY: 'http.request.body',
3
5
  HTTP_REQUEST_PARAMETER: 'http.request.parameter'
@@ -1,3 +1,5 @@
1
+ 'use strict'
2
+
1
3
  const Plugin = require('../../../plugins/plugin')
2
4
  const { getIastContext } = require('../iast-context')
3
5
  const { storage } = require('../../../../../datadog-core')
@@ -2,7 +2,7 @@
2
2
 
3
3
  const Module = require('module')
4
4
  const shimmer = require('../../../../../datadog-shimmer')
5
- const log = require('../../../log')
5
+ const iastLog = require('../iast-log')
6
6
  const { isPrivateModule, isNotLibraryFile } = require('./filter')
7
7
  const { csiMethods } = require('./csi-methods')
8
8
 
@@ -16,7 +16,8 @@ function getRewriter () {
16
16
  getPrepareStackTrace = iastRewriter.getPrepareStackTrace
17
17
  rewriter = new Rewriter({ csiMethods })
18
18
  } catch (e) {
19
- log.warn(`Unable to initialize TaintTracking Rewriter: ${e.message}`)
19
+ iastLog.error('Unable to initialize TaintTracking Rewriter')
20
+ .errorAndPublish(e)
20
21
  }
21
22
  }
22
23
  return rewriter
@@ -46,7 +47,8 @@ function getCompileMethodFn (compileMethod) {
46
47
  }
47
48
  }
48
49
  } catch (e) {
49
- log.error(e)
50
+ iastLog.error(`Error rewriting ${filename}`)
51
+ .errorAndPublish(e)
50
52
  }
51
53
  return compileMethod.apply(this, [content, filename])
52
54
  }
@@ -3,7 +3,7 @@
3
3
  const TaintedUtils = require('@datadog/native-iast-taint-tracking')
4
4
  const { storage } = require('../../../../../datadog-core')
5
5
  const iastContextFunctions = require('../iast-context')
6
- const log = require('../../../log')
6
+ const iastLog = require('../iast-log')
7
7
 
8
8
  function noop (res) { return res }
9
9
  const TaintTrackingDummy = {
@@ -32,7 +32,8 @@ function getFilteredCsiFn (cb, filter) {
32
32
  return cb(transactionId, res, target, ...rest)
33
33
  }
34
34
  } catch (e) {
35
- log.debug(e)
35
+ iastLog.error(`Error invoking CSI ${target}`)
36
+ .errorAndPublish(e)
36
37
  }
37
38
  return res
38
39
  }
@@ -80,7 +81,8 @@ const csiMethodsOverrides = {
80
81
  return TaintedUtils.concat(transactionId, res, op1, op2)
81
82
  }
82
83
  } catch (e) {
83
- log.debug(e)
84
+ iastLog.error(`Error invoking CSI plusOperator`)
85
+ .errorAndPublish(e)
84
86
  }
85
87
  return res
86
88
  },
@@ -0,0 +1,96 @@
1
+ 'use strict'
2
+
3
+ const log = require('../../../log')
4
+
5
+ const logs = new Map()
6
+
7
+ // NOTE: Is this a reasonable number?
8
+ let maxEntries = 10000
9
+ let overflowedCount = 0
10
+
11
+ function hashCode (hashSource) {
12
+ let hash = 0
13
+ const size = hashSource.length
14
+ for (let offset = 0; offset < size; offset++) {
15
+ hash = (((hash * 31) | 0) + hashSource.charCodeAt(offset)) | 0
16
+ }
17
+ return hash
18
+ }
19
+
20
+ function createHash (logEntry) {
21
+ if (!logEntry) return 0
22
+
23
+ const prime = 31
24
+ let result = ((!logEntry.level) ? 0 : hashCode(logEntry.level))
25
+ result = (((prime * result) | 0) + ((!logEntry.message) ? 0 : hashCode(logEntry.message))) | 0
26
+
27
+ // NOTE: tags are not used at the moment
28
+ // result = (((prime * result) | 0) + ((!logEntry.tags) ? 0 : hashCode(logEntry.tags))) | 0
29
+ result = (((prime * result) | 0) + ((!logEntry.stack_trace) ? 0 : hashCode(logEntry.stack_trace))) | 0
30
+ return result
31
+ }
32
+
33
+ function newLogEntry (message, level, tags) {
34
+ return {
35
+ message,
36
+ level,
37
+ tags
38
+ }
39
+ }
40
+
41
+ function isValid (logEntry) {
42
+ return logEntry && logEntry.level && logEntry.message
43
+ }
44
+
45
+ const logCollector = {
46
+ add (logEntry) {
47
+ try {
48
+ if (!isValid(logEntry)) {
49
+ log.info('IAST log collector discarding invalid log')
50
+ return
51
+ }
52
+
53
+ // NOTE: should errors have higher priority? and discard log entries with lower priority?
54
+ if (logs.size >= maxEntries) {
55
+ overflowedCount++
56
+ return
57
+ }
58
+
59
+ const hash = createHash(logEntry)
60
+ if (!logs.has(hash)) {
61
+ logs.set(hash, logEntry)
62
+ return true
63
+ }
64
+ } catch (e) {
65
+ log.error(`Unable to add log to logCollector: ${e.message}`)
66
+ }
67
+ return false
68
+ },
69
+
70
+ drain () {
71
+ if (logs.size === 0) return
72
+
73
+ const drained = []
74
+ drained.push(...logs.values())
75
+
76
+ if (overflowedCount > 0) {
77
+ drained.push(newLogEntry(`Omitted ${overflowedCount} entries due to overflowing`, 'ERROR'))
78
+ }
79
+
80
+ this.reset()
81
+
82
+ return drained
83
+ },
84
+
85
+ reset (max) {
86
+ logs.clear()
87
+ overflowedCount = 0
88
+ if (max) {
89
+ maxEntries = max
90
+ }
91
+ }
92
+ }
93
+
94
+ logCollector.reset()
95
+
96
+ module.exports = logCollector
@@ -0,0 +1,87 @@
1
+ 'use strict'
2
+
3
+ const dc = require('diagnostics_channel')
4
+ const logCollector = require('./log_collector')
5
+ const { sendData } = require('../../../telemetry/send-data')
6
+ const log = require('../../../log')
7
+
8
+ const telemetryStartChannel = dc.channel('datadog:telemetry:start')
9
+ const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
10
+
11
+ let config, application, host, interval
12
+
13
+ function publish (log) {
14
+ if (log && isLevelEnabled(log.level)) {
15
+ logCollector.add(log)
16
+ }
17
+ }
18
+
19
+ function sendLogs () {
20
+ try {
21
+ const logs = logCollector.drain()
22
+ if (logs) {
23
+ sendData(config, application, host, 'logs', logs)
24
+ }
25
+ } catch (e) {
26
+ log.error(e)
27
+ }
28
+ }
29
+
30
+ function isLevelEnabled (level) {
31
+ return isLogCollectionEnabled(config) && (level !== 'DEBUG' || config.telemetry.debug)
32
+ }
33
+
34
+ function isLogCollectionEnabled (config) {
35
+ return config && config.telemetry && config.telemetry.logCollection
36
+ }
37
+
38
+ function onTelemetryStart (msg) {
39
+ if (!msg || !isLogCollectionEnabled(msg.config)) {
40
+ log.info('IAST telemetry logs start received but log collection is not enabled or configuration is incorrect')
41
+ return false
42
+ }
43
+
44
+ log.info('IAST telemetry logs starting')
45
+
46
+ config = msg.config
47
+ application = msg.application
48
+ host = msg.host
49
+
50
+ if (msg.heartbeatInterval) {
51
+ interval = setInterval(sendLogs, msg.heartbeatInterval)
52
+ interval.unref()
53
+ }
54
+
55
+ return true
56
+ }
57
+
58
+ function onTelemetryStop () {
59
+ stop()
60
+ }
61
+
62
+ function start () {
63
+ telemetryStartChannel.subscribe(onTelemetryStart)
64
+ telemetryStopChannel.subscribe(onTelemetryStop)
65
+ }
66
+
67
+ function stop () {
68
+ if (!isLogCollectionEnabled(config)) return
69
+
70
+ log.info('IAST telemetry logs stopping')
71
+
72
+ config = null
73
+ application = null
74
+ host = null
75
+
76
+ if (telemetryStartChannel.hasSubscribers) {
77
+ telemetryStartChannel.unsubscribe(onTelemetryStart)
78
+ }
79
+
80
+ if (telemetryStopChannel.hasSubscribers) {
81
+ telemetryStopChannel.unsubscribe(onTelemetryStop)
82
+ }
83
+
84
+ clearInterval(interval)
85
+ }
86
+
87
+ module.exports = { start, stop, publish, isLevelEnabled }
@@ -4,8 +4,11 @@ const VULNERABILITIES_KEY = 'vulnerabilities'
4
4
  const IAST_JSON_TAG_KEY = '_dd.iast.json'
5
5
  const VULNERABILITY_HASHES_MAX_SIZE = 1000
6
6
  const VULNERABILITY_HASHES = new LRU({ max: VULNERABILITY_HASHES_MAX_SIZE })
7
+ const RESET_VULNERABILITY_CACHE_INTERVAL = 60 * 60 * 1000 // 1 hour
7
8
 
8
9
  let tracer
10
+ let resetVulnerabilityCacheTimer
11
+ let deduplicationEnabled = true
9
12
 
10
13
  function createVulnerability (type, evidence, spanId, location) {
11
14
  if (type && evidence) {
@@ -164,7 +167,20 @@ function clearCache () { // only for test purposes
164
167
  VULNERABILITY_HASHES.clear()
165
168
  }
166
169
 
170
+ function startClearCacheTimer () {
171
+ resetVulnerabilityCacheTimer = setInterval(clearCache, RESET_VULNERABILITY_CACHE_INTERVAL)
172
+ resetVulnerabilityCacheTimer.unref()
173
+ }
174
+
175
+ function stopClearCacheTimer () {
176
+ if (resetVulnerabilityCacheTimer) {
177
+ clearInterval(resetVulnerabilityCacheTimer)
178
+ resetVulnerabilityCacheTimer = null
179
+ }
180
+ }
181
+
167
182
  function deduplicateVulnerabilities (vulnerabilities) {
183
+ if (!deduplicationEnabled) return vulnerabilities
168
184
  const deduplicated = vulnerabilities.filter((vulnerability) => {
169
185
  const key = `${vulnerability.type}${vulnerability.hash}`
170
186
  if (!VULNERABILITY_HASHES.get(key)) {
@@ -176,14 +192,23 @@ function deduplicateVulnerabilities (vulnerabilities) {
176
192
  return deduplicated
177
193
  }
178
194
 
179
- function setTracer (_tracer) {
195
+ function start (config, _tracer) {
196
+ deduplicationEnabled = config.iast.deduplicationEnabled
197
+ if (deduplicationEnabled) {
198
+ startClearCacheTimer()
199
+ }
180
200
  tracer = _tracer
181
201
  }
182
202
 
203
+ function stop () {
204
+ stopClearCacheTimer()
205
+ }
206
+
183
207
  module.exports = {
184
208
  createVulnerability,
185
209
  addVulnerability,
186
210
  sendVulnerabilities,
187
211
  clearCache,
188
- setTracer
212
+ start,
213
+ stop
189
214
  }
@@ -1,7 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const fs = require('fs')
4
- const path = require('path')
5
3
  const log = require('../log')
6
4
  const RuleManager = require('./rule_manager')
7
5
  const remoteConfig = require('./remote_config')
@@ -12,7 +10,7 @@ const Reporter = require('./reporter')
12
10
  const web = require('../plugins/util/web')
13
11
  const { extractIp } = require('../plugins/util/ip_extractor')
14
12
  const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
15
- const { block, loadTemplates, loadTemplatesAsync } = require('./blocking')
13
+ const { block, setTemplates } = require('./blocking')
16
14
 
17
15
  let isEnabled = false
18
16
  let config
@@ -21,21 +19,10 @@ function enable (_config) {
21
19
  if (isEnabled) return
22
20
 
23
21
  try {
24
- loadTemplates(_config)
25
- const rules = fs.readFileSync(_config.appsec.rules || path.join(__dirname, 'recommended.json'))
26
- enableFromRules(_config, JSON.parse(rules))
27
- } catch (err) {
28
- abortEnable(err)
29
- }
30
- }
22
+ setTemplates(_config)
31
23
 
32
- async function enableAsync (_config) {
33
- if (isEnabled) return
34
-
35
- try {
36
- await loadTemplatesAsync(_config)
37
- const rules = await fs.promises.readFile(_config.appsec.rules || path.join(__dirname, 'recommended.json'))
38
- enableFromRules(_config, JSON.parse(rules))
24
+ // TODO: inline this function
25
+ enableFromRules(_config, _config.appsec.rules)
39
26
  } catch (err) {
40
27
  abortEnable(err)
41
28
  }
@@ -169,7 +156,6 @@ function disable () {
169
156
 
170
157
  module.exports = {
171
158
  enable,
172
- enableAsync,
173
159
  disable,
174
160
  incomingHttpStartTranslator,
175
161
  incomingHttpEndTranslator
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.5.2"
4
+ "rules_version": "1.6.0"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -2907,7 +2907,8 @@
2907
2907
  }
2908
2908
  ],
2909
2909
  "transformers": [
2910
- "removeNulls"
2910
+ "removeNulls",
2911
+ "urlDecodeUni"
2911
2912
  ]
2912
2913
  },
2913
2914
  {
@@ -2957,7 +2958,8 @@
2957
2958
  }
2958
2959
  ],
2959
2960
  "transformers": [
2960
- "removeNulls"
2961
+ "removeNulls",
2962
+ "urlDecodeUni"
2961
2963
  ]
2962
2964
  },
2963
2965
  {
@@ -3007,7 +3009,8 @@
3007
3009
  }
3008
3010
  ],
3009
3011
  "transformers": [
3010
- "removeNulls"
3012
+ "removeNulls",
3013
+ "urlDecodeUni"
3011
3014
  ]
3012
3015
  },
3013
3016
  {
@@ -3054,7 +3057,8 @@
3054
3057
  }
3055
3058
  ],
3056
3059
  "transformers": [
3057
- "removeNulls"
3060
+ "removeNulls",
3061
+ "urlDecodeUni"
3058
3062
  ]
3059
3063
  },
3060
3064
  {
@@ -3088,8 +3092,7 @@
3088
3092
  ".parentnode",
3089
3093
  ".innerhtml",
3090
3094
  "window.location",
3091
- "-moz-binding",
3092
- "<![cdata["
3095
+ "-moz-binding"
3093
3096
  ]
3094
3097
  },
3095
3098
  "operator": "phrase_match"
@@ -3545,7 +3548,7 @@
3545
3548
  "address": "grpc.server.request.message"
3546
3549
  }
3547
3550
  ],
3548
- "regex": "\\b(?i:eval|settimeout|setinterval|new\\s+Function|alert|prompt)\\s*\\([^\\)]",
3551
+ "regex": "\\b(?i:eval|settimeout|setinterval|new\\s+Function|alert|prompt)[\\s+]*\\([^\\)]",
3549
3552
  "options": {
3550
3553
  "case_sensitive": true,
3551
3554
  "min_length": 5
@@ -5347,14 +5350,12 @@
5347
5350
  "address": "grpc.server.request.message"
5348
5351
  }
5349
5352
  ],
5350
- "regex": "(http|https):\\/\\/(?:.*\\.)?(?:burpcollaborator\\.net|localtest\\.me|mail\\.ebc\\.apple\\.com|bugbounty\\.dod\\.network|.*\\.[nx]ip\\.io|oastify\\.com|oast\\.(?:pro|live|site|online|fun|me)|sslip\\.io|requestbin\\.com|requestbin\\.net|hookbin\\.com|webhook\\.site|canarytokens\\.com|interact\\.sh|ngrok\\.io|bugbounty\\.click|prbly\\.win|qualysperiscope\\.com)"
5353
+ "regex": "(http|https):\\/\\/(?:.*\\.)?(?:burpcollaborator\\.net|localtest\\.me|mail\\.ebc\\.apple\\.com|bugbounty\\.dod\\.network|.*\\.[nx]ip\\.io|oastify\\.com|oast\\.(?:pro|live|site|online|fun|me)|sslip\\.io|requestbin\\.com|requestbin\\.net|hookbin\\.com|webhook\\.site|canarytokens\\.com|interact\\.sh|ngrok\\.io|bugbounty\\.click|prbly\\.win|qualysperiscope\\.com|vii.one|act1on3.ru)"
5351
5354
  },
5352
5355
  "operator": "match_regex"
5353
5356
  }
5354
5357
  ],
5355
- "transformers": [
5356
- "lowercase"
5357
- ]
5358
+ "transformers": []
5358
5359
  },
5359
5360
  {
5360
5361
  "id": "sqr-000-015",
@@ -5429,7 +5430,9 @@
5429
5430
  "operator": "match_regex"
5430
5431
  }
5431
5432
  ],
5432
- "transformers": []
5433
+ "transformers": [
5434
+ "unicode_normalize"
5435
+ ]
5433
5436
  },
5434
5437
  {
5435
5438
  "id": "ua0-600-0xx",
@@ -5905,7 +5908,7 @@
5905
5908
  "tags": {
5906
5909
  "type": "security_scanner",
5907
5910
  "category": "attack_attempt",
5908
- "confidence": "1"
5911
+ "confidence": "0"
5909
5912
  },
5910
5913
  "conditions": [
5911
5914
  {
@@ -6616,6 +6619,32 @@
6616
6619
  "block"
6617
6620
  ]
6618
6621
  },
6622
+ {
6623
+ "id": "ua0-600-57x",
6624
+ "name": "AlertLogic",
6625
+ "tags": {
6626
+ "type": "security_scanner",
6627
+ "category": "attack_attempt",
6628
+ "confidence": "0"
6629
+ },
6630
+ "conditions": [
6631
+ {
6632
+ "parameters": {
6633
+ "inputs": [
6634
+ {
6635
+ "address": "server.request.headers.no_cookies",
6636
+ "key_path": [
6637
+ "user-agent"
6638
+ ]
6639
+ }
6640
+ ],
6641
+ "regex": "\\bAlertLogic-MDR-"
6642
+ },
6643
+ "operator": "match_regex"
6644
+ }
6645
+ ],
6646
+ "transformers": []
6647
+ },
6619
6648
  {
6620
6649
  "id": "ua0-600-5xx",
6621
6650
  "name": "Blind SQL Injection Brute Forcer",
@@ -23,7 +23,7 @@ function enable (config) {
23
23
  }
24
24
 
25
25
  if (shouldEnable) {
26
- require('..').enableAsync(config).catch(() => {})
26
+ require('..').enable(config)
27
27
  } else {
28
28
  require('..').disable()
29
29
  }
@@ -2,14 +2,14 @@
2
2
 
3
3
  const { trackUserLoginSuccessEvent, trackUserLoginFailureEvent, trackCustomEvent } = require('./track_event')
4
4
  const { checkUserAndSetUser, blockRequest } = require('./user_blocking')
5
- const { loadTemplates } = require('../blocking')
5
+ const { setTemplates } = require('../blocking')
6
6
  const { setUser } = require('./set_user')
7
7
 
8
8
  class AppsecSdk {
9
9
  constructor (tracer, config) {
10
10
  this._tracer = tracer
11
11
  if (config) {
12
- loadTemplates(config)
12
+ setTemplates(config)
13
13
  }
14
14
  }
15
15
 
@@ -0,0 +1,27 @@
1
+ 'use strict'
2
+
3
+ class JSONEncoder {
4
+ constructor () {
5
+ this.payloads = []
6
+ }
7
+
8
+ encode (payload) {
9
+ this.payloads.push(payload)
10
+ }
11
+
12
+ count () {
13
+ return this.payloads.length
14
+ }
15
+
16
+ reset () {
17
+ this.payloads = []
18
+ }
19
+
20
+ makePayload () {
21
+ const data = JSON.stringify(this.payloads)
22
+ this.reset()
23
+ return data
24
+ }
25
+ }
26
+
27
+ module.exports = { JSONEncoder }