dd-trace 5.19.0 → 5.20.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 (40) hide show
  1. package/ext/formats.d.ts +1 -0
  2. package/ext/formats.js +2 -1
  3. package/init.js +3 -15
  4. package/package.json +3 -2
  5. package/packages/datadog-instrumentations/src/helpers/register.js +13 -11
  6. package/packages/datadog-instrumentations/src/http/client.js +7 -1
  7. package/packages/datadog-instrumentations/src/http/server.js +50 -13
  8. package/packages/datadog-instrumentations/src/mocha/main.js +21 -8
  9. package/packages/datadog-instrumentations/src/process.js +29 -0
  10. package/packages/datadog-instrumentations/src/vitest.js +47 -23
  11. package/packages/datadog-plugin-aws-sdk/src/base.js +15 -1
  12. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  13. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
  14. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +3 -3
  15. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +37 -8
  16. package/packages/datadog-plugin-vitest/src/index.js +2 -1
  17. package/packages/dd-trace/src/appsec/blocking.js +10 -1
  18. package/packages/dd-trace/src/appsec/channels.js +4 -1
  19. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  20. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +16 -0
  21. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -0
  22. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -1
  23. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +11 -0
  24. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/code-injection-sensitive-analyzer.js +25 -0
  25. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  26. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  27. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  28. package/packages/dd-trace/src/appsec/index.js +12 -7
  29. package/packages/dd-trace/src/appsec/rasp.js +121 -7
  30. package/packages/dd-trace/src/appsec/recommended.json +220 -2
  31. package/packages/dd-trace/src/config.js +41 -42
  32. package/packages/dd-trace/src/data_streams.js +44 -0
  33. package/packages/dd-trace/src/datastreams/pathway.js +4 -2
  34. package/packages/dd-trace/src/log/index.js +32 -0
  35. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +43 -0
  36. package/packages/dd-trace/src/opentracing/tracer.js +10 -6
  37. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -2
  38. package/packages/dd-trace/src/plugins/plugin.js +12 -1
  39. package/packages/dd-trace/src/proxy.js +1 -0
  40. package/packages/dd-trace/src/tracer.js +2 -0
@@ -9,6 +9,8 @@ let templateHtml = blockedTemplates.html
9
9
  let templateJson = blockedTemplates.json
10
10
  let templateGraphqlJson = blockedTemplates.graphqlJson
11
11
 
12
+ const responseBlockedSet = new WeakSet()
13
+
12
14
  const specificBlockingTypes = {
13
15
  GRAPHQL: 'graphql'
14
16
  }
@@ -117,6 +119,8 @@ function block (req, res, rootSpan, abortController, actionParameters) {
117
119
 
118
120
  res.writeHead(statusCode, headers).end(body)
119
121
 
122
+ responseBlockedSet.add(res)
123
+
120
124
  abortController?.abort()
121
125
  }
122
126
 
@@ -144,11 +148,16 @@ function setTemplates (config) {
144
148
  }
145
149
  }
146
150
 
151
+ function isBlocked (res) {
152
+ return responseBlockedSet.has(res)
153
+ }
154
+
147
155
  module.exports = {
148
156
  addSpecificEndpoint,
149
157
  block,
150
158
  specificBlockingTypes,
151
159
  getBlockingData,
152
160
  getBlockingAction,
153
- setTemplates
161
+ setTemplates,
162
+ isBlocked
154
163
  }
@@ -19,5 +19,8 @@ module.exports = {
19
19
  nextQueryParsed: dc.channel('apm:next:query-parsed'),
20
20
  responseBody: dc.channel('datadog:express:response:json:start'),
21
21
  responseWriteHead: dc.channel('apm:http:server:response:writeHead:start'),
22
- httpClientRequestStart: dc.channel('apm:http:client:request:start')
22
+ httpClientRequestStart: dc.channel('apm:http:client:request:start'),
23
+ responseSetHeader: dc.channel('datadog:http:server:response:set-header:start'),
24
+ setUncaughtExceptionCaptureCallbackStart: dc.channel('datadog:process:setUncaughtExceptionCaptureCallback:start')
25
+
23
26
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  module.exports = {
4
+ CODE_INJECTION_ANALYZER: require('./code-injection-analyzer'),
4
5
  COMMAND_INJECTION_ANALYZER: require('./command-injection-analyzer'),
5
6
  HARCODED_PASSWORD_ANALYZER: require('./hardcoded-password-analyzer'),
6
7
  HARCODED_SECRET_ANALYZER: require('./hardcoded-secret-analyzer'),
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ const InjectionAnalyzer = require('./injection-analyzer')
4
+ const { CODE_INJECTION } = require('../vulnerabilities')
5
+
6
+ class CodeInjectionAnalyzer extends InjectionAnalyzer {
7
+ constructor () {
8
+ super(CODE_INJECTION)
9
+ }
10
+
11
+ onConfigure () {
12
+ this.addSub('datadog:eval:call', ({ script }) => this.analyze(script))
13
+ }
14
+ }
15
+
16
+ module.exports = new CodeInjectionAnalyzer()
@@ -47,6 +47,8 @@ class WeakHashAnalyzer extends Analyzer {
47
47
  }
48
48
 
49
49
  _isExcluded (location) {
50
+ if (!location) return false
51
+
50
52
  return EXCLUDED_LOCATIONS.some(excludedLocation => {
51
53
  return location.path.includes(excludedLocation)
52
54
  })
@@ -14,7 +14,8 @@ const csiMethods = [
14
14
  { src: 'toUpperCase', dst: 'stringCase' },
15
15
  { src: 'trim' },
16
16
  { src: 'trimEnd' },
17
- { src: 'trimStart', dst: 'trim' }
17
+ { src: 'trimStart', dst: 'trim' },
18
+ { src: 'eval', allowedWithoutCallee: true }
18
19
  ]
19
20
 
20
21
  module.exports = {
@@ -10,6 +10,7 @@ const { isDebugAllowed } = require('../telemetry/verbosity')
10
10
  const { taintObject } = require('./operations-taint-object')
11
11
 
12
12
  const mathRandomCallCh = dc.channel('datadog:random:call')
13
+ const evalCallCh = dc.channel('datadog:eval:call')
13
14
 
14
15
  const JSON_VALUE = 'json.value'
15
16
 
@@ -18,6 +19,7 @@ function noop (res) { return res }
18
19
  // Otherwise you may end up rewriting a method and not providing its rewritten implementation
19
20
  const TaintTrackingNoop = {
20
21
  concat: noop,
22
+ eval: noop,
21
23
  join: noop,
22
24
  parse: noop,
23
25
  plusOperator: noop,
@@ -136,6 +138,15 @@ function csiMethodsOverrides (getContext) {
136
138
  return res
137
139
  },
138
140
 
141
+ eval: function (res, fn, target, script) {
142
+ // eslint-disable-next-line no-eval
143
+ if (evalCallCh.hasSubscribers && fn === globalThis.eval) {
144
+ evalCallCh.publish({ script })
145
+ }
146
+
147
+ return res
148
+ },
149
+
139
150
  parse: function (res, fn, target, json) {
140
151
  if (fn === JSON.parse) {
141
152
  try {
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ module.exports = function extractSensitiveRanges (evidence) {
4
+ const newRanges = []
5
+ if (evidence.ranges[0].start > 0) {
6
+ newRanges.push({
7
+ start: 0,
8
+ end: evidence.ranges[0].start
9
+ })
10
+ }
11
+
12
+ for (let i = 0; i < evidence.ranges.length; i++) {
13
+ const currentRange = evidence.ranges[i]
14
+ const nextRange = evidence.ranges[i + 1]
15
+
16
+ const start = currentRange.end
17
+ const end = nextRange?.start || evidence.value.length
18
+
19
+ if (start < end) {
20
+ newRanges.push({ start, end })
21
+ }
22
+ }
23
+
24
+ return newRanges
25
+ }
@@ -5,6 +5,7 @@ const vulnerabilities = require('../../vulnerabilities')
5
5
 
6
6
  const { contains, intersects, remove } = require('./range-utils')
7
7
 
8
+ const codeInjectionSensitiveAnalyzer = require('./sensitive-analyzers/code-injection-sensitive-analyzer')
8
9
  const commandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
9
10
  const hardcodedPasswordAnalyzer = require('./sensitive-analyzers/hardcoded-password-analyzer')
10
11
  const headerSensitiveAnalyzer = require('./sensitive-analyzers/header-sensitive-analyzer')
@@ -23,6 +24,7 @@ class SensitiveHandler {
23
24
  this._valuePattern = new RegExp(DEFAULT_IAST_REDACTION_VALUE_PATTERN, 'gmi')
24
25
 
25
26
  this._sensitiveAnalyzers = new Map()
27
+ this._sensitiveAnalyzers.set(vulnerabilities.CODE_INJECTION, codeInjectionSensitiveAnalyzer)
26
28
  this._sensitiveAnalyzers.set(vulnerabilities.COMMAND_INJECTION, commandSensitiveAnalyzer)
27
29
  this._sensitiveAnalyzers.set(vulnerabilities.NOSQL_MONGODB_INJECTION, jsonSensitiveAnalyzer)
28
30
  this._sensitiveAnalyzers.set(vulnerabilities.LDAP_INJECTION, ldapSensitiveAnalyzer)
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line max-len
2
- const DEFAULT_IAST_REDACTION_NAME_PATTERN = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)'
2
+ const DEFAULT_IAST_REDACTION_NAME_PATTERN = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|(?:sur|last)name|user(?:name)?|address|e?mail)'
3
3
  // eslint-disable-next-line max-len
4
- const DEFAULT_IAST_REDACTION_VALUE_PATTERN = '(?:bearer\\s+[a-z0-9\\._\\-]+|glpat-[\\w\\-]{20}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=\\-]+\\.ey[I-L][\\w=\\-]+(?:\\.[\\w.+/=\\-]+)?|(?:[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY[\\-]{5}|ssh-rsa\\s*[a-z0-9/\\.+]{100,}))'
4
+ const DEFAULT_IAST_REDACTION_VALUE_PATTERN = '(?:bearer\\s+[a-z0-9\\._\\-]+|glpat-[\\w\\-]{20}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=\\-]+\\.ey[I-L][\\w=\\-]+(?:\\.[\\w.+/=\\-]+)?|(?:[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY[\\-]{5}|ssh-rsa\\s*[a-z0-9/\\.+]{100,})|[\\w\\.-]+@[a-zA-Z\\d\\.-]+\\.[a-zA-Z]{2,})'
5
5
 
6
6
  module.exports = {
7
7
  DEFAULT_IAST_REDACTION_NAME_PATTERN,
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  COMMAND_INJECTION: 'COMMAND_INJECTION',
3
+ CODE_INJECTION: 'CODE_INJECTION',
3
4
  HARDCODED_PASSWORD: 'HARDCODED_PASSWORD',
4
5
  HARDCODED_SECRET: 'HARDCODED_SECRET',
5
6
  HEADER_INJECTION: 'HEADER_INJECTION',
@@ -13,7 +13,8 @@ const {
13
13
  nextBodyParsed,
14
14
  nextQueryParsed,
15
15
  responseBody,
16
- responseWriteHead
16
+ responseWriteHead,
17
+ responseSetHeader
17
18
  } = require('./channels')
18
19
  const waf = require('./waf')
19
20
  const addresses = require('./addresses')
@@ -23,7 +24,7 @@ const apiSecuritySampler = require('./api_security_sampler')
23
24
  const web = require('../plugins/util/web')
24
25
  const { extractIp } = require('../plugins/util/ip_extractor')
25
26
  const { HTTP_CLIENT_IP } = require('../../../../ext/tags')
26
- const { block, setTemplates, getBlockingAction } = require('./blocking')
27
+ const { isBlocked, block, setTemplates, getBlockingAction } = require('./blocking')
27
28
  const { passportTrackEvent } = require('./passport')
28
29
  const { storage } = require('../../../datadog-core')
29
30
  const graphql = require('./graphql')
@@ -62,6 +63,7 @@ function enable (_config) {
62
63
  cookieParser.subscribe(onRequestCookieParser)
63
64
  responseBody.subscribe(onResponseBody)
64
65
  responseWriteHead.subscribe(onResponseWriteHead)
66
+ responseSetHeader.subscribe(onResponseSetHeader)
65
67
 
66
68
  if (_config.appsec.eventTracking.enabled) {
67
69
  passportVerify.subscribe(onPassportVerify)
@@ -223,11 +225,10 @@ function onPassportVerify ({ credentials, user }) {
223
225
  }
224
226
 
225
227
  const responseAnalyzedSet = new WeakSet()
226
- const responseBlockedSet = new WeakSet()
227
228
 
228
229
  function onResponseWriteHead ({ req, res, abortController, statusCode, responseHeaders }) {
229
230
  // avoid "write after end" error
230
- if (responseBlockedSet.has(res)) {
231
+ if (isBlocked(res)) {
231
232
  abortController?.abort()
232
233
  return
233
234
  }
@@ -255,15 +256,18 @@ function onResponseWriteHead ({ req, res, abortController, statusCode, responseH
255
256
  handleResults(results, req, res, rootSpan, abortController)
256
257
  }
257
258
 
259
+ function onResponseSetHeader ({ res, abortController }) {
260
+ if (isBlocked(res)) {
261
+ abortController?.abort()
262
+ }
263
+ }
264
+
258
265
  function handleResults (actions, req, res, rootSpan, abortController) {
259
266
  if (!actions || !req || !res || !rootSpan || !abortController) return
260
267
 
261
268
  const blockingAction = getBlockingAction(actions)
262
269
  if (blockingAction) {
263
270
  block(req, res, rootSpan, abortController, blockingAction)
264
- if (!abortController.signal || abortController.signal.aborted) {
265
- responseBlockedSet.add(res)
266
- }
267
271
  }
268
272
  }
269
273
 
@@ -290,6 +294,7 @@ function disable () {
290
294
  if (responseBody.hasSubscribers) responseBody.unsubscribe(onResponseBody)
291
295
  if (passportVerify.hasSubscribers) passportVerify.unsubscribe(onPassportVerify)
292
296
  if (responseWriteHead.hasSubscribers) responseWriteHead.unsubscribe(onResponseWriteHead)
297
+ if (responseSetHeader.hasSubscribers) responseSetHeader.unsubscribe(onResponseSetHeader)
293
298
  }
294
299
 
295
300
  module.exports = {
@@ -3,23 +3,118 @@
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const web = require('./../plugins/util/web')
5
5
  const addresses = require('./addresses')
6
- const { httpClientRequestStart } = require('./channels')
6
+ const { httpClientRequestStart, setUncaughtExceptionCaptureCallbackStart } = require('./channels')
7
7
  const { reportStackTrace } = require('./stack_trace')
8
8
  const waf = require('./waf')
9
+ const { getBlockingAction, block } = require('./blocking')
10
+ const log = require('../log')
9
11
 
10
12
  const RULE_TYPES = {
11
13
  SSRF: 'ssrf'
12
14
  }
13
15
 
14
- let config
16
+ class DatadogRaspAbortError extends Error {
17
+ constructor (req, res, blockingAction) {
18
+ super('DatadogRaspAbortError')
19
+ this.name = 'DatadogRaspAbortError'
20
+ this.req = req
21
+ this.res = res
22
+ this.blockingAction = blockingAction
23
+ }
24
+ }
25
+
26
+ let config, abortOnUncaughtException
27
+
28
+ function removeAllListeners (emitter, event) {
29
+ const listeners = emitter.listeners(event)
30
+ emitter.removeAllListeners(event)
31
+
32
+ let cleaned = false
33
+ return function () {
34
+ if (cleaned === true) {
35
+ return
36
+ }
37
+ cleaned = true
38
+
39
+ for (let i = 0; i < listeners.length; ++i) {
40
+ emitter.on(event, listeners[i])
41
+ }
42
+ }
43
+ }
44
+
45
+ function findDatadogRaspAbortError (err, deep = 10) {
46
+ if (err instanceof DatadogRaspAbortError) {
47
+ return err
48
+ }
49
+
50
+ if (err.cause && deep > 0) {
51
+ return findDatadogRaspAbortError(err.cause, deep - 1)
52
+ }
53
+ }
54
+
55
+ function handleUncaughtExceptionMonitor (err) {
56
+ const abortError = findDatadogRaspAbortError(err)
57
+ if (!abortError) return
58
+
59
+ const { req, res, blockingAction } = abortError
60
+ block(req, res, web.root(req), null, blockingAction)
61
+
62
+ if (!process.hasUncaughtExceptionCaptureCallback()) {
63
+ const cleanUp = removeAllListeners(process, 'uncaughtException')
64
+ const handler = () => {
65
+ process.removeListener('uncaughtException', handler)
66
+ }
67
+
68
+ setTimeout(() => {
69
+ process.removeListener('uncaughtException', handler)
70
+ cleanUp()
71
+ })
72
+
73
+ process.on('uncaughtException', handler)
74
+ } else {
75
+ // uncaughtException event is not executed when hasUncaughtExceptionCaptureCallback is true
76
+ let previousCb
77
+ const cb = ({ currentCallback, abortController }) => {
78
+ setUncaughtExceptionCaptureCallbackStart.unsubscribe(cb)
79
+ if (!currentCallback) {
80
+ abortController.abort()
81
+ return
82
+ }
83
+
84
+ previousCb = currentCallback
85
+ }
86
+
87
+ setUncaughtExceptionCaptureCallbackStart.subscribe(cb)
88
+
89
+ process.setUncaughtExceptionCaptureCallback(null)
90
+
91
+ // For some reason, previous callback was defined before the instrumentation
92
+ // We can not restore it, so we let the app decide
93
+ if (previousCb) {
94
+ process.setUncaughtExceptionCaptureCallback(() => {
95
+ process.setUncaughtExceptionCaptureCallback(null)
96
+ process.setUncaughtExceptionCaptureCallback(previousCb)
97
+ })
98
+ }
99
+ }
100
+ }
15
101
 
16
102
  function enable (_config) {
17
103
  config = _config
18
104
  httpClientRequestStart.subscribe(analyzeSsrf)
105
+
106
+ process.on('uncaughtExceptionMonitor', handleUncaughtExceptionMonitor)
107
+ abortOnUncaughtException = process.execArgv?.includes('--abort-on-uncaught-exception')
108
+
109
+ if (abortOnUncaughtException) {
110
+ log.warn('The --abort-on-uncaught-exception flag is enabled. The RASP module will not block operations.')
111
+ }
19
112
  }
20
113
 
21
114
  function disable () {
22
115
  if (httpClientRequestStart.hasSubscribers) httpClientRequestStart.unsubscribe(analyzeSsrf)
116
+
117
+ process.off('uncaughtExceptionMonitor', handleUncaughtExceptionMonitor)
23
118
  }
24
119
 
25
120
  function analyzeSsrf (ctx) {
@@ -32,17 +127,18 @@ function analyzeSsrf (ctx) {
32
127
  const persistent = {
33
128
  [addresses.HTTP_OUTGOING_URL]: url
34
129
  }
35
- // TODO: Currently this is only monitoring, we should
36
- // block the request if SSRF attempt
130
+
37
131
  const result = waf.run({ persistent }, req, RULE_TYPES.SSRF)
38
- handleResult(result, req)
132
+
133
+ const res = store?.res
134
+ handleResult(result, req, res, ctx.abortController)
39
135
  }
40
136
 
41
137
  function getGenerateStackTraceAction (actions) {
42
138
  return actions?.generate_stack
43
139
  }
44
140
 
45
- function handleResult (actions, req) {
141
+ function handleResult (actions, req, res, abortController) {
46
142
  const generateStackTraceAction = getGenerateStackTraceAction(actions)
47
143
  if (generateStackTraceAction && config.appsec.stackTrace.enabled) {
48
144
  const rootSpan = web.root(req)
@@ -53,10 +149,28 @@ function handleResult (actions, req) {
53
149
  config.appsec.stackTrace.maxStackTraces
54
150
  )
55
151
  }
152
+
153
+ if (!abortController || abortOnUncaughtException) return
154
+
155
+ const blockingAction = getBlockingAction(actions)
156
+ if (blockingAction) {
157
+ const rootSpan = web.root(req)
158
+ // Should block only in express
159
+ if (rootSpan?.context()._name === 'express.request') {
160
+ const abortError = new DatadogRaspAbortError(req, res, blockingAction)
161
+ abortController.abort(abortError)
162
+
163
+ // TODO Delete this when support for node 16 is removed
164
+ if (!abortController.signal.reason) {
165
+ abortController.signal.reason = abortError
166
+ }
167
+ }
168
+ }
56
169
  }
57
170
 
58
171
  module.exports = {
59
172
  enable,
60
173
  disable,
61
- handleResult
174
+ handleResult,
175
+ handleUncaughtExceptionMonitor // exported only for testing purpose
62
176
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.12.0"
4
+ "rules_version": "1.13.0"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -6285,6 +6285,55 @@
6285
6285
  "stack_trace"
6286
6286
  ]
6287
6287
  },
6288
+ {
6289
+ "id": "rasp-932-100",
6290
+ "name": "Shell injection exploit",
6291
+ "enabled": false,
6292
+ "tags": {
6293
+ "type": "command_injection",
6294
+ "category": "vulnerability_trigger",
6295
+ "cwe": "77",
6296
+ "capec": "1000/152/248/88",
6297
+ "confidence": "0",
6298
+ "module": "rasp"
6299
+ },
6300
+ "conditions": [
6301
+ {
6302
+ "parameters": {
6303
+ "resource": [
6304
+ {
6305
+ "address": "server.sys.shell.cmd"
6306
+ }
6307
+ ],
6308
+ "params": [
6309
+ {
6310
+ "address": "server.request.query"
6311
+ },
6312
+ {
6313
+ "address": "server.request.body"
6314
+ },
6315
+ {
6316
+ "address": "server.request.path_params"
6317
+ },
6318
+ {
6319
+ "address": "grpc.server.request.message"
6320
+ },
6321
+ {
6322
+ "address": "graphql.server.all_resolvers"
6323
+ },
6324
+ {
6325
+ "address": "graphql.server.resolver"
6326
+ }
6327
+ ]
6328
+ },
6329
+ "operator": "shi_detector"
6330
+ }
6331
+ ],
6332
+ "transformers": [],
6333
+ "on_match": [
6334
+ "stack_trace"
6335
+ ]
6336
+ },
6288
6337
  {
6289
6338
  "id": "rasp-934-100",
6290
6339
  "name": "Server-side request forgery exploit",
@@ -8388,6 +8437,57 @@
8388
8437
  }
8389
8438
  ],
8390
8439
  "processors": [
8440
+ {
8441
+ "id": "http-endpoint-fingerprint",
8442
+ "generator": "http_endpoint_fingerprint",
8443
+ "conditions": [
8444
+ {
8445
+ "operator": "exists",
8446
+ "parameters": {
8447
+ "inputs": [
8448
+ {
8449
+ "address": "waf.context.event"
8450
+ },
8451
+ {
8452
+ "address": "server.business_logic.users.login.failure"
8453
+ },
8454
+ {
8455
+ "address": "server.business_logic.users.login.success"
8456
+ }
8457
+ ]
8458
+ }
8459
+ }
8460
+ ],
8461
+ "parameters": {
8462
+ "mappings": [
8463
+ {
8464
+ "method": [
8465
+ {
8466
+ "address": "server.request.method"
8467
+ }
8468
+ ],
8469
+ "uri_raw": [
8470
+ {
8471
+ "address": "server.request.uri.raw"
8472
+ }
8473
+ ],
8474
+ "body": [
8475
+ {
8476
+ "address": "server.request.body"
8477
+ }
8478
+ ],
8479
+ "query": [
8480
+ {
8481
+ "address": "server.request.query"
8482
+ }
8483
+ ],
8484
+ "output": "_dd.appsec.fp.http.endpoint"
8485
+ }
8486
+ ]
8487
+ },
8488
+ "evaluate": false,
8489
+ "output": true
8490
+ },
8391
8491
  {
8392
8492
  "id": "extract-content",
8393
8493
  "generator": "extract_schema",
@@ -8537,6 +8637,124 @@
8537
8637
  },
8538
8638
  "evaluate": false,
8539
8639
  "output": true
8640
+ },
8641
+ {
8642
+ "id": "http-header-fingerprint",
8643
+ "generator": "http_header_fingerprint",
8644
+ "conditions": [
8645
+ {
8646
+ "operator": "exists",
8647
+ "parameters": {
8648
+ "inputs": [
8649
+ {
8650
+ "address": "waf.context.event"
8651
+ },
8652
+ {
8653
+ "address": "server.business_logic.users.login.failure"
8654
+ },
8655
+ {
8656
+ "address": "server.business_logic.users.login.success"
8657
+ }
8658
+ ]
8659
+ }
8660
+ }
8661
+ ],
8662
+ "parameters": {
8663
+ "mappings": [
8664
+ {
8665
+ "headers": [
8666
+ {
8667
+ "address": "server.request.headers.no_cookies"
8668
+ }
8669
+ ],
8670
+ "output": "_dd.appsec.fp.http.header"
8671
+ }
8672
+ ]
8673
+ },
8674
+ "evaluate": false,
8675
+ "output": true
8676
+ },
8677
+ {
8678
+ "id": "http-network-fingerprint",
8679
+ "generator": "http_network_fingerprint",
8680
+ "conditions": [
8681
+ {
8682
+ "operator": "exists",
8683
+ "parameters": {
8684
+ "inputs": [
8685
+ {
8686
+ "address": "waf.context.event"
8687
+ },
8688
+ {
8689
+ "address": "server.business_logic.users.login.failure"
8690
+ },
8691
+ {
8692
+ "address": "server.business_logic.users.login.success"
8693
+ }
8694
+ ]
8695
+ }
8696
+ }
8697
+ ],
8698
+ "parameters": {
8699
+ "mappings": [
8700
+ {
8701
+ "headers": [
8702
+ {
8703
+ "address": "server.request.headers.no_cookies"
8704
+ }
8705
+ ],
8706
+ "output": "_dd.appsec.fp.http.network"
8707
+ }
8708
+ ]
8709
+ },
8710
+ "evaluate": false,
8711
+ "output": true
8712
+ },
8713
+ {
8714
+ "id": "session-fingerprint",
8715
+ "generator": "session_fingerprint",
8716
+ "conditions": [
8717
+ {
8718
+ "operator": "exists",
8719
+ "parameters": {
8720
+ "inputs": [
8721
+ {
8722
+ "address": "waf.context.event"
8723
+ },
8724
+ {
8725
+ "address": "server.business_logic.users.login.failure"
8726
+ },
8727
+ {
8728
+ "address": "server.business_logic.users.login.success"
8729
+ }
8730
+ ]
8731
+ }
8732
+ }
8733
+ ],
8734
+ "parameters": {
8735
+ "mappings": [
8736
+ {
8737
+ "cookies": [
8738
+ {
8739
+ "address": "server.request.cookies"
8740
+ }
8741
+ ],
8742
+ "session_id": [
8743
+ {
8744
+ "address": "usr.session_id"
8745
+ }
8746
+ ],
8747
+ "user_id": [
8748
+ {
8749
+ "address": "usr.id"
8750
+ }
8751
+ ],
8752
+ "output": "_dd.appsec.fp.session"
8753
+ }
8754
+ ]
8755
+ },
8756
+ "evaluate": false,
8757
+ "output": true
8540
8758
  }
8541
8759
  ],
8542
8760
  "scanners": [
@@ -9562,4 +9780,4 @@
9562
9780
  }
9563
9781
  }
9564
9782
  ]
9565
- }
9783
+ }