dd-trace 3.14.1 → 3.16.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 (187) hide show
  1. package/LICENSE-3rdparty.csv +2 -2
  2. package/README.md +9 -5
  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 +36 -3
  7. package/package.json +21 -19
  8. package/packages/datadog-instrumentations/src/cucumber.js +80 -3
  9. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +100 -27
  10. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  11. package/packages/datadog-instrumentations/src/jest.js +35 -3
  12. package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
  13. package/packages/datadog-instrumentations/src/mariadb.js +130 -11
  14. package/packages/datadog-instrumentations/src/mocha.js +30 -6
  15. package/packages/datadog-instrumentations/src/mongodb-core.js +8 -2
  16. package/packages/datadog-instrumentations/src/mongoose.js +1 -1
  17. package/packages/datadog-instrumentations/src/next.js +33 -4
  18. package/packages/datadog-instrumentations/src/playwright.js +42 -13
  19. package/packages/datadog-plugin-amqp10/src/consumer.js +1 -1
  20. package/packages/datadog-plugin-amqp10/src/index.js +1 -1
  21. package/packages/datadog-plugin-amqp10/src/producer.js +3 -2
  22. package/packages/datadog-plugin-amqplib/src/client.js +3 -2
  23. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  24. package/packages/datadog-plugin-amqplib/src/index.js +1 -1
  25. package/packages/datadog-plugin-amqplib/src/producer.js +3 -2
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +7 -2
  27. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -1
  28. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +2 -0
  29. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +2 -0
  30. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -0
  31. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -0
  32. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +2 -0
  33. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +2 -0
  34. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +2 -0
  35. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
  36. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -0
  37. package/packages/datadog-plugin-bunyan/src/index.js +1 -1
  38. package/packages/datadog-plugin-cassandra-driver/src/index.js +3 -2
  39. package/packages/datadog-plugin-connect/src/index.js +1 -1
  40. package/packages/datadog-plugin-couchbase/src/index.js +1 -1
  41. package/packages/datadog-plugin-cucumber/src/index.js +33 -6
  42. package/packages/datadog-plugin-cypress/src/index.js +1 -1
  43. package/packages/datadog-plugin-cypress/src/plugin.js +40 -33
  44. package/packages/datadog-plugin-dns/src/index.js +1 -1
  45. package/packages/datadog-plugin-dns/src/lookup.js +1 -1
  46. package/packages/datadog-plugin-dns/src/lookup_service.js +1 -1
  47. package/packages/datadog-plugin-dns/src/resolve.js +1 -1
  48. package/packages/datadog-plugin-dns/src/reverse.js +1 -1
  49. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  50. package/packages/datadog-plugin-express/src/index.js +1 -1
  51. package/packages/datadog-plugin-fastify/src/index.js +1 -1
  52. package/packages/datadog-plugin-find-my-way/src/index.js +1 -1
  53. package/packages/datadog-plugin-fs/src/index.js +1 -1
  54. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +5 -5
  55. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  56. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -1
  57. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +7 -6
  58. package/packages/datadog-plugin-graphql/src/execute.js +1 -1
  59. package/packages/datadog-plugin-graphql/src/index.js +1 -1
  60. package/packages/datadog-plugin-graphql/src/parse.js +1 -1
  61. package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
  62. package/packages/datadog-plugin-graphql/src/validate.js +1 -1
  63. package/packages/datadog-plugin-grpc/src/client.js +1 -1
  64. package/packages/datadog-plugin-grpc/src/index.js +1 -1
  65. package/packages/datadog-plugin-grpc/src/server.js +1 -1
  66. package/packages/datadog-plugin-hapi/src/index.js +1 -1
  67. package/packages/datadog-plugin-http/src/client.js +2 -2
  68. package/packages/datadog-plugin-http/src/index.js +1 -1
  69. package/packages/datadog-plugin-http/src/server.js +3 -3
  70. package/packages/datadog-plugin-http2/src/client.js +4 -3
  71. package/packages/datadog-plugin-http2/src/index.js +1 -1
  72. package/packages/datadog-plugin-http2/src/server.js +3 -3
  73. package/packages/datadog-plugin-ioredis/src/index.js +1 -1
  74. package/packages/datadog-plugin-jest/src/index.js +53 -19
  75. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -1
  76. package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
  77. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
  78. package/packages/datadog-plugin-koa/src/index.js +1 -1
  79. package/packages/datadog-plugin-mariadb/src/index.js +18 -1
  80. package/packages/datadog-plugin-memcached/src/index.js +3 -2
  81. package/packages/datadog-plugin-microgateway-core/src/index.js +1 -1
  82. package/packages/datadog-plugin-mocha/src/index.js +13 -9
  83. package/packages/datadog-plugin-moleculer/src/client.js +1 -1
  84. package/packages/datadog-plugin-moleculer/src/index.js +1 -1
  85. package/packages/datadog-plugin-moleculer/src/server.js +1 -1
  86. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
  87. package/packages/datadog-plugin-mysql/src/index.js +3 -2
  88. package/packages/datadog-plugin-mysql2/src/index.js +1 -1
  89. package/packages/datadog-plugin-net/src/index.js +9 -75
  90. package/packages/datadog-plugin-net/src/ipc.js +1 -1
  91. package/packages/datadog-plugin-net/src/tcp.js +3 -2
  92. package/packages/datadog-plugin-next/src/index.js +3 -3
  93. package/packages/datadog-plugin-opensearch/src/index.js +1 -1
  94. package/packages/datadog-plugin-oracledb/src/index.js +3 -2
  95. package/packages/datadog-plugin-paperplane/src/index.js +1 -1
  96. package/packages/datadog-plugin-paperplane/src/logger.js +1 -1
  97. package/packages/datadog-plugin-paperplane/src/server.js +1 -1
  98. package/packages/datadog-plugin-pg/src/index.js +3 -2
  99. package/packages/datadog-plugin-pino/src/index.js +1 -1
  100. package/packages/datadog-plugin-playwright/src/index.js +5 -4
  101. package/packages/datadog-plugin-redis/src/index.js +3 -2
  102. package/packages/datadog-plugin-restify/src/index.js +1 -1
  103. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  104. package/packages/datadog-plugin-rhea/src/index.js +1 -1
  105. package/packages/datadog-plugin-rhea/src/producer.js +3 -2
  106. package/packages/datadog-plugin-router/src/index.js +8 -8
  107. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  108. package/packages/datadog-plugin-tedious/src/index.js +3 -2
  109. package/packages/datadog-plugin-web/src/index.js +1 -1
  110. package/packages/datadog-plugin-winston/src/index.js +1 -1
  111. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  112. package/packages/dd-trace/src/appsec/blocking.js +35 -9
  113. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +2 -1
  114. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
  115. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +2 -2
  116. package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
  117. package/packages/dd-trace/src/appsec/iast/iast-log.js +111 -0
  118. package/packages/dd-trace/src/appsec/iast/index.js +10 -6
  119. package/packages/dd-trace/src/appsec/iast/path-line.js +3 -6
  120. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +2 -0
  121. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -0
  122. package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +2 -0
  123. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -0
  124. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -4
  125. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +5 -3
  126. package/packages/dd-trace/src/appsec/iast/telemetry/log_collector.js +96 -0
  127. package/packages/dd-trace/src/appsec/iast/telemetry/logs.js +87 -0
  128. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +27 -2
  129. package/packages/dd-trace/src/appsec/index.js +4 -4
  130. package/packages/dd-trace/src/appsec/recommended.json +76 -75
  131. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  132. package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
  133. package/packages/dd-trace/src/appsec/sdk/index.js +19 -1
  134. package/packages/dd-trace/src/appsec/sdk/noop.js +6 -0
  135. package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
  136. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -2
  137. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
  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 +17 -9
  140. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +14 -8
  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 +12 -4
  144. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +12 -4
  145. package/packages/dd-trace/src/config.js +24 -5
  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/exporter.js +7 -9
  149. package/packages/dd-trace/src/exporters/common/agents.js +42 -0
  150. package/packages/dd-trace/src/exporters/common/docker.js +4 -1
  151. package/packages/dd-trace/src/exporters/common/request.js +1 -4
  152. package/packages/dd-trace/src/lambda/handler.js +19 -12
  153. package/packages/dd-trace/src/log/writer.js +32 -24
  154. package/packages/dd-trace/src/metrics.js +18 -0
  155. package/packages/dd-trace/src/noop/proxy.js +2 -2
  156. package/packages/dd-trace/src/opentracing/span.js +5 -0
  157. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  158. package/packages/dd-trace/src/plugin_manager.js +7 -7
  159. package/packages/dd-trace/src/plugins/ci_plugin.js +20 -17
  160. package/packages/dd-trace/src/plugins/index.js +1 -0
  161. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  162. package/packages/dd-trace/src/plugins/outgoing.js +2 -1
  163. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  164. package/packages/dd-trace/src/plugins/util/ci.js +12 -0
  165. package/packages/dd-trace/src/plugins/util/exec.js +2 -2
  166. package/packages/dd-trace/src/plugins/util/git.js +16 -1
  167. package/packages/dd-trace/src/plugins/util/ip_extractor.js +23 -27
  168. package/packages/dd-trace/src/plugins/util/test.js +26 -7
  169. package/packages/dd-trace/src/profiler.js +3 -0
  170. package/packages/dd-trace/src/profiling/config.js +92 -20
  171. package/packages/dd-trace/src/profiling/constants.js +16 -0
  172. package/packages/dd-trace/src/profiling/exporter_cli.js +62 -0
  173. package/packages/dd-trace/src/profiling/exporters/agent.js +2 -1
  174. package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
  175. package/packages/dd-trace/src/profiling/profiler.js +42 -12
  176. package/packages/dd-trace/src/profiling/profilers/space.js +21 -1
  177. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
  178. package/packages/dd-trace/src/proxy.js +1 -1
  179. package/packages/dd-trace/src/span_processor.js +1 -1
  180. package/packages/dd-trace/src/span_sampler.js +71 -54
  181. package/packages/dd-trace/src/startup-log.js +3 -6
  182. package/packages/dd-trace/src/telemetry/index.js +16 -2
  183. package/packages/dd-trace/src/tracer.js +0 -16
  184. package/packages/dd-trace/src/util.js +10 -1
  185. package/scripts/install_plugin_modules.js +5 -1
  186. package/scripts/junit_report.js +0 -25
  187. package/scripts/tdd.js +0 -34
@@ -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
@@ -40,10 +41,14 @@ function getCompileMethodFn (compileMethod) {
40
41
  return function (content, filename) {
41
42
  try {
42
43
  if (isPrivateModule(filename) && isNotLibraryFile(filename)) {
43
- content = rewriter.rewrite(content, filename)
44
+ const rewritten = rewriter.rewrite(content, filename)
45
+ if (rewritten && rewritten.content) {
46
+ return compileMethod.apply(this, [rewritten.content, filename])
47
+ }
44
48
  }
45
49
  } catch (e) {
46
- log.debug(e)
50
+ iastLog.error(`Error rewriting ${filename}`)
51
+ .errorAndPublish(e)
47
52
  }
48
53
  return compileMethod.apply(this, [content, filename])
49
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
  }
@@ -70,12 +70,12 @@ function abortEnable (err) {
70
70
  }
71
71
 
72
72
  function incomingHttpStartTranslator ({ req, res, abortController }) {
73
- const topSpan = web.root(req)
74
- if (!topSpan) return
73
+ const rootSpan = web.root(req)
74
+ if (!rootSpan) return
75
75
 
76
76
  const clientIp = extractIp(config, req)
77
77
 
78
- topSpan.addTags({
78
+ rootSpan.addTags({
79
79
  '_dd.appsec.enabled': 1,
80
80
  '_dd.runtime_family': 'nodejs',
81
81
  [HTTP_CLIENT_IP]: clientIp
@@ -97,7 +97,7 @@ function incomingHttpStartTranslator ({ req, res, abortController }) {
97
97
 
98
98
  for (const entry of results) {
99
99
  if (entry && entry.includes('block')) {
100
- block(req, res, topSpan, abortController)
100
+ block(req, res, rootSpan, abortController)
101
101
  break
102
102
  }
103
103
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.5.0"
4
+ "rules_version": "1.5.2"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -199,33 +199,6 @@
199
199
  "lowercase"
200
200
  ]
201
201
  },
202
- {
203
- "id": "crs-921-140",
204
- "name": "HTTP Header Injection Attack via headers",
205
- "tags": {
206
- "type": "http_protocol_violation",
207
- "crs_id": "921140",
208
- "category": "attack_attempt"
209
- },
210
- "conditions": [
211
- {
212
- "parameters": {
213
- "inputs": [
214
- {
215
- "address": "server.request.headers.no_cookies"
216
- }
217
- ],
218
- "regex": "[\\n\\r]",
219
- "options": {
220
- "case_sensitive": true,
221
- "min_length": 1
222
- }
223
- },
224
- "operator": "match_regex"
225
- }
226
- ],
227
- "transformers": []
228
- },
229
202
  {
230
203
  "id": "crs-921-160",
231
204
  "name": "HTTP Header Injection Attack via payload (CR/LF and header-name detected)",
@@ -245,7 +218,7 @@
245
218
  "address": "server.request.path_params"
246
219
  }
247
220
  ],
248
- "regex": "[\\n\\r]+(?:\\s|location|refresh|(?:set-)?cookie|(?:x-)?(?:forwarded-(?:for|host|server)|host|via|remote-ip|remote-addr|originating-IP))\\s*:",
221
+ "regex": "[\\n\\r]+(?:refresh|(?:set-)?cookie|(?:x-)?(?:forwarded-(?:for|host|server)|via|remote-ip|remote-addr|originating-IP))\\s*:",
249
222
  "options": {
250
223
  "case_sensitive": true,
251
224
  "min_length": 3
@@ -278,7 +251,7 @@
278
251
  "address": "server.request.headers.no_cookies"
279
252
  }
280
253
  ],
281
- "regex": "(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/|\\x5c)(?:%(?:(?:f(?:(?:c%80|8)%8)?0%8|e)0%80%ae|2(?:(?:5(?:c0%25a|2))?e|%45)|u(?:(?:002|ff0)e|2024)|%32(?:%(?:%6|4)5|E)|c0(?:%[256aef]e|\\.))|\\.(?:%0[01]|\\?)?|\\?\\.?|0x2e){2,3}(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/|\\x5c)",
254
+ "regex": "(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/|\\x5c)(?:%(?:(?:f(?:(?:c%80|8)%8)?0%8|e)0%80%ae|2(?:(?:5(?:c0%25a|2))?e|%45)|u(?:(?:002|ff0)e|2024)|%32(?:%(?:%6|4)5|E)|c0(?:%[256aef]e|\\.))|\\.(?:%0[01])?|0x2e){2,3}(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5c)|0x(?:2f|5c)|\\/|\\x5c)",
282
255
  "options": {
283
256
  "min_length": 4
284
257
  }
@@ -1378,16 +1351,11 @@
1378
1351
  "etc/timezone",
1379
1352
  "etc/modules",
1380
1353
  "etc/passwd",
1381
- "etc/passwd~",
1382
- "etc/passwd-",
1383
1354
  "etc/shadow",
1384
- "etc/shadow~",
1385
- "etc/shadow-",
1386
1355
  "etc/fstab",
1387
1356
  "etc/motd",
1388
1357
  "etc/hosts",
1389
1358
  "etc/group",
1390
- "etc/group-",
1391
1359
  "etc/alias",
1392
1360
  "etc/crontab",
1393
1361
  "etc/crypttab",
@@ -1834,7 +1802,7 @@
1834
1802
  "address": "server.request.path_params"
1835
1803
  }
1836
1804
  ],
1837
- "regex": "^(?i:file|ftps?|http)://.*?\\?+$",
1805
+ "regex": "^(?i:file|ftps?)://.*?\\?+$",
1838
1806
  "options": {
1839
1807
  "case_sensitive": true,
1840
1808
  "min_length": 4
@@ -1898,11 +1866,8 @@
1898
1866
  "dev/tcp/",
1899
1867
  "dev/udp/",
1900
1868
  "dev/zero",
1901
- "etc/group",
1902
1869
  "etc/master.passwd",
1903
- "etc/passwd",
1904
1870
  "etc/pwd.db",
1905
- "etc/shadow",
1906
1871
  "etc/shells",
1907
1872
  "etc/spwd.db",
1908
1873
  "proc/self/",
@@ -4117,9 +4082,7 @@
4117
4082
  "java.lang.number",
4118
4083
  "java.lang.object",
4119
4084
  "java.lang.process",
4120
- "java.lang.processbuilder",
4121
4085
  "java.lang.reflect",
4122
- "java.lang.runtime",
4123
4086
  "java.lang.string",
4124
4087
  "java.lang.stringbuilder",
4125
4088
  "java.lang.system",
@@ -4452,6 +4415,74 @@
4452
4415
  ],
4453
4416
  "transformers": []
4454
4417
  },
4418
+ {
4419
+ "id": "dog-934-001",
4420
+ "name": "XXE - XML file loads external entity",
4421
+ "tags": {
4422
+ "type": "xxe",
4423
+ "category": "attack_attempt",
4424
+ "confidence": "0"
4425
+ },
4426
+ "conditions": [
4427
+ {
4428
+ "parameters": {
4429
+ "inputs": [
4430
+ {
4431
+ "address": "server.request.body"
4432
+ },
4433
+ {
4434
+ "address": "grpc.server.request.message"
4435
+ }
4436
+ ],
4437
+ "regex": "(?:<\\?xml[^>]*>.*)<!ENTITY[^>]+SYSTEM\\s+[^>]+>",
4438
+ "options": {
4439
+ "case_sensitive": false,
4440
+ "min_length": 24
4441
+ }
4442
+ },
4443
+ "operator": "match_regex"
4444
+ }
4445
+ ],
4446
+ "transformers": []
4447
+ },
4448
+ {
4449
+ "id": "dog-942-001",
4450
+ "name": "Blind XSS callback domains",
4451
+ "tags": {
4452
+ "type": "xss",
4453
+ "category": "attack_attempt",
4454
+ "confidence": "1"
4455
+ },
4456
+ "conditions": [
4457
+ {
4458
+ "parameters": {
4459
+ "inputs": [
4460
+ {
4461
+ "address": "server.request.query"
4462
+ },
4463
+ {
4464
+ "address": "server.request.body"
4465
+ },
4466
+ {
4467
+ "address": "server.request.path_params"
4468
+ },
4469
+ {
4470
+ "address": "server.request.headers.no_cookies"
4471
+ },
4472
+ {
4473
+ "address": "grpc.server.request.message"
4474
+ }
4475
+ ],
4476
+ "regex": "https?:\\/\\/(?:.*\\.)?(?:bxss\\.in|xss\\.ht|js\\.rip)",
4477
+ "options": {
4478
+ "case_sensitive": false
4479
+ }
4480
+ },
4481
+ "operator": "match_regex"
4482
+ }
4483
+ ],
4484
+ "transformers": []
4485
+ },
4455
4486
  {
4456
4487
  "id": "nfd-000-001",
4457
4488
  "name": "Detect common directory discovery scans",
@@ -5080,36 +5111,6 @@
5080
5111
  "removeNulls"
5081
5112
  ]
5082
5113
  },
5083
- {
5084
- "id": "sqr-000-007",
5085
- "name": "NoSQL: Detect common exploitation strategy",
5086
- "tags": {
5087
- "type": "nosql_injection",
5088
- "category": "attack_attempt"
5089
- },
5090
- "conditions": [
5091
- {
5092
- "parameters": {
5093
- "inputs": [
5094
- {
5095
- "address": "server.request.query"
5096
- },
5097
- {
5098
- "address": "server.request.body"
5099
- },
5100
- {
5101
- "address": "server.request.path_params"
5102
- }
5103
- ],
5104
- "regex": "^\\$(eq|ne|(l|g)te?|n?in|not|(n|x|)or|and|regex|where|expr|exists)$"
5105
- },
5106
- "operator": "match_regex"
5107
- }
5108
- ],
5109
- "transformers": [
5110
- "keys_only"
5111
- ]
5112
- },
5113
5114
  {
5114
5115
  "id": "sqr-000-008",
5115
5116
  "name": "Windows: Detect attempts to exfiltrate .ini files",
@@ -5275,7 +5276,7 @@
5275
5276
  "address": "grpc.server.request.message"
5276
5277
  }
5277
5278
  ],
5278
- "regex": "^(jar:)?(http|https):\\/\\/([0-9oq]{1,5}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|[0-9]{1,10})(:[0-9]{1,5})?(\\/.*|)$"
5279
+ "regex": "^(jar:)?(http|https):\\/\\/([0-9oq]{1,5}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}|[0-9]{1,10})(:[0-9]{1,5})?(\\/[^:@]*)?$"
5279
5280
  },
5280
5281
  "operator": "match_regex"
5281
5282
  }
@@ -5309,7 +5310,7 @@
5309
5310
  "address": "grpc.server.request.message"
5310
5311
  }
5311
5312
  ],
5312
- "regex": "^(jar:)?(http|https):\\/\\/((\\[)?[:0-9a-f\\.x]{2,}(\\])?)(:[0-9]{1,5})?(\\/.*)?$"
5313
+ "regex": "^(jar:)?(http|https):\\/\\/((\\[)?[:0-9a-f\\.x]{2,}(\\])?)(:[0-9]{1,5})?(\\/[^:@]*)?$"
5313
5314
  },
5314
5315
  "operator": "match_regex"
5315
5316
  }
@@ -5346,7 +5347,7 @@
5346
5347
  "address": "grpc.server.request.message"
5347
5348
  }
5348
5349
  ],
5349
- "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)"
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)"
5350
5351
  },
5351
5352
  "operator": "match_regex"
5352
5353
  }
@@ -6720,4 +6721,4 @@
6720
6721
  "transformers": []
6721
6722
  }
6722
6723
  ]
6723
- }
6724
+ }
@@ -3,5 +3,6 @@
3
3
  module.exports = {
4
4
  ASM_ACTIVATION: 1n << 1n,
5
5
  ASM_IP_BLOCKING: 1n << 2n,
6
- ASM_DD_RULES: 1n << 3n
6
+ ASM_DD_RULES: 1n << 3n,
7
+ ASM_USER_BLOCKING: 1n << 7n
7
8
  }
@@ -35,12 +35,15 @@ function enable (config) {
35
35
  function enableAsmData (appsecConfig) {
36
36
  if (rc && appsecConfig && appsecConfig.rules === undefined) {
37
37
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, true)
38
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, true)
38
39
  rc.on('ASM_DATA', _asmDataListener)
39
40
  }
40
41
  }
41
42
 
42
43
  function disableAsmData () {
43
44
  if (rc) {
45
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, false)
46
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, false)
44
47
  rc.off('ASM_DATA', _asmDataListener)
45
48
  }
46
49
  }
@@ -1,10 +1,16 @@
1
1
  'use strict'
2
2
 
3
3
  const { trackUserLoginSuccessEvent, trackUserLoginFailureEvent, trackCustomEvent } = require('./track_event')
4
+ const { checkUserAndSetUser, blockRequest } = require('./user_blocking')
5
+ const { loadTemplates } = require('../blocking')
6
+ const { setUser } = require('./set_user')
4
7
 
5
8
  class AppsecSdk {
6
- constructor (tracer) {
9
+ constructor (tracer, config) {
7
10
  this._tracer = tracer
11
+ if (config) {
12
+ loadTemplates(config)
13
+ }
8
14
  }
9
15
 
10
16
  trackUserLoginSuccessEvent (user, metadata) {
@@ -18,6 +24,18 @@ class AppsecSdk {
18
24
  trackCustomEvent (eventName, metadata) {
19
25
  return trackCustomEvent(this._tracer, eventName, metadata)
20
26
  }
27
+
28
+ isUserBlocked (user) {
29
+ return checkUserAndSetUser(this._tracer, user)
30
+ }
31
+
32
+ blockRequest (req, res) {
33
+ return blockRequest(this._tracer, req, res)
34
+ }
35
+
36
+ setUser (user) {
37
+ return setUser(this._tracer, user)
38
+ }
21
39
  }
22
40
 
23
41
  module.exports = AppsecSdk
@@ -6,6 +6,12 @@ class NoopAppsecSdk {
6
6
  trackUserLoginFailureEvent () {}
7
7
 
8
8
  trackCustomEvent () {}
9
+
10
+ isUserBlocked () {}
11
+
12
+ blockRequest () {}
13
+
14
+ setUser () {}
9
15
  }
10
16
 
11
17
  module.exports = NoopAppsecSdk
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ const { getRootSpan } = require('./utils')
4
+ const log = require('../../log')
5
+
6
+ function setUserTags (user, rootSpan) {
7
+ for (const k of Object.keys(user)) {
8
+ rootSpan.setTag(`usr.${k}`, '' + user[k])
9
+ }
10
+ }
11
+
12
+ function setUser (tracer, user) {
13
+ if (!user || !user.id) {
14
+ log.warn('Invalid user provided to setUser')
15
+ return
16
+ }
17
+
18
+ const rootSpan = getRootSpan(tracer)
19
+ if (!rootSpan) {
20
+ log.warn('Root span not available in setUser')
21
+ return
22
+ }
23
+
24
+ setUserTags(user, rootSpan)
25
+ }
26
+
27
+ module.exports = {
28
+ setUserTags,
29
+ setUser
30
+ }