dd-trace 5.25.0 → 5.27.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 (74) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +17 -8
  3. package/init.js +60 -47
  4. package/package.json +5 -2
  5. package/packages/datadog-core/index.js +1 -3
  6. package/packages/datadog-core/src/storage.js +21 -0
  7. package/packages/datadog-instrumentations/src/express.js +1 -1
  8. package/packages/datadog-instrumentations/src/handlebars.js +40 -0
  9. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  10. package/packages/datadog-instrumentations/src/jest.js +6 -2
  11. package/packages/datadog-instrumentations/src/langchain.js +77 -0
  12. package/packages/datadog-instrumentations/src/next.js +19 -7
  13. package/packages/datadog-instrumentations/src/pug.js +23 -0
  14. package/packages/datadog-instrumentations/src/router.js +2 -3
  15. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
  16. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +7 -6
  17. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +34 -0
  18. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +8 -8
  19. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
  20. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  21. package/packages/datadog-plugin-http/src/client.js +42 -1
  22. package/packages/datadog-plugin-http2/src/client.js +26 -1
  23. package/packages/datadog-plugin-langchain/src/handlers/chain.js +50 -0
  24. package/packages/datadog-plugin-langchain/src/handlers/default.js +53 -0
  25. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +63 -0
  26. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +99 -0
  27. package/packages/datadog-plugin-langchain/src/handlers/language_models/index.js +48 -0
  28. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +57 -0
  29. package/packages/datadog-plugin-langchain/src/index.js +89 -0
  30. package/packages/datadog-plugin-langchain/src/tokens.js +35 -0
  31. package/packages/datadog-plugin-mocha/src/index.js +1 -1
  32. package/packages/datadog-plugin-moleculer/src/server.js +0 -1
  33. package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
  34. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  35. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
  36. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
  37. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
  38. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  39. package/packages/dd-trace/src/appsec/index.js +6 -6
  40. package/packages/dd-trace/src/appsec/recommended.json +353 -155
  41. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -1
  42. package/packages/dd-trace/src/appsec/remote_config/index.js +0 -7
  43. package/packages/dd-trace/src/appsec/reporter.js +1 -0
  44. package/packages/dd-trace/src/appsec/sdk/utils.js +21 -2
  45. package/packages/dd-trace/src/config.js +21 -4
  46. package/packages/dd-trace/src/constants.js +6 -1
  47. package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
  48. package/packages/dd-trace/src/crashtracking/index.js +15 -0
  49. package/packages/dd-trace/src/crashtracking/noop.js +8 -0
  50. package/packages/dd-trace/src/llmobs/sdk.js +1 -1
  51. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  52. package/packages/dd-trace/src/llmobs/writers/spans/base.js +3 -0
  53. package/packages/dd-trace/src/log/index.js +10 -13
  54. package/packages/dd-trace/src/log/log.js +52 -0
  55. package/packages/dd-trace/src/log/writer.js +50 -19
  56. package/packages/dd-trace/src/noop/span.js +1 -0
  57. package/packages/dd-trace/src/opentelemetry/span.js +15 -0
  58. package/packages/dd-trace/src/opentracing/propagation/text_map.js +35 -22
  59. package/packages/dd-trace/src/opentracing/span.js +14 -0
  60. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  61. package/packages/dd-trace/src/plugins/index.js +3 -0
  62. package/packages/dd-trace/src/plugins/tracing.js +2 -2
  63. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
  64. package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
  65. package/packages/dd-trace/src/plugins/util/web.js +39 -11
  66. package/packages/dd-trace/src/profiling/exporters/agent.js +42 -5
  67. package/packages/dd-trace/src/profiling/profiler.js +5 -2
  68. package/packages/dd-trace/src/proxy.js +5 -0
  69. package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
  70. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
  71. package/packages/dd-trace/src/telemetry/metrics.js +6 -1
  72. package/packages/dd-trace/src/util.js +16 -1
  73. package/version.js +4 -2
  74. /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
@@ -0,0 +1,89 @@
1
+ 'use strict'
2
+
3
+ const { MEASURED } = require('../../../ext/tags')
4
+ const { storage } = require('../../datadog-core')
5
+ const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
6
+
7
+ const API_KEY = 'langchain.request.api_key'
8
+ const MODEL = 'langchain.request.model'
9
+ const PROVIDER = 'langchain.request.provider'
10
+ const TYPE = 'langchain.request.type'
11
+
12
+ const LangChainHandler = require('./handlers/default')
13
+ const LangChainChatModelHandler = require('./handlers/language_models/chat_model')
14
+ const LangChainLLMHandler = require('./handlers/language_models/llm')
15
+ const LangChainChainHandler = require('./handlers/chain')
16
+ const LangChainEmbeddingHandler = require('./handlers/embedding')
17
+
18
+ class LangChainPlugin extends TracingPlugin {
19
+ static get id () { return 'langchain' }
20
+ static get operation () { return 'invoke' }
21
+ static get system () { return 'langchain' }
22
+ static get prefix () {
23
+ return 'tracing:apm:langchain:invoke'
24
+ }
25
+
26
+ constructor () {
27
+ super(...arguments)
28
+
29
+ const langchainConfig = this._tracerConfig.langchain || {}
30
+ this.handlers = {
31
+ chain: new LangChainChainHandler(langchainConfig),
32
+ chat_model: new LangChainChatModelHandler(langchainConfig),
33
+ llm: new LangChainLLMHandler(langchainConfig),
34
+ embedding: new LangChainEmbeddingHandler(langchainConfig),
35
+ default: new LangChainHandler(langchainConfig)
36
+ }
37
+ }
38
+
39
+ bindStart (ctx) {
40
+ const { resource, type } = ctx
41
+ const handler = this.handlers[type]
42
+
43
+ const instance = ctx.instance
44
+ const apiKey = handler.extractApiKey(instance)
45
+ const provider = handler.extractProvider(instance)
46
+ const model = handler.extractModel(instance)
47
+
48
+ const tags = handler.getSpanStartTags(ctx, provider) || []
49
+
50
+ if (apiKey) tags[API_KEY] = apiKey
51
+ if (provider) tags[PROVIDER] = provider
52
+ if (model) tags[MODEL] = model
53
+ if (type) tags[TYPE] = type
54
+
55
+ const span = this.startSpan('langchain.request', {
56
+ service: this.config.service,
57
+ resource,
58
+ kind: 'client',
59
+ meta: {
60
+ [MEASURED]: 1,
61
+ ...tags
62
+ }
63
+ }, false)
64
+
65
+ const store = storage.getStore() || {}
66
+ ctx.currentStore = { ...store, span }
67
+
68
+ return ctx.currentStore
69
+ }
70
+
71
+ asyncEnd (ctx) {
72
+ const span = ctx.currentStore.span
73
+
74
+ const { type } = ctx
75
+
76
+ const handler = this.handlers[type]
77
+ const tags = handler.getSpanEndTags(ctx) || {}
78
+
79
+ span.addTags(tags)
80
+
81
+ span.finish()
82
+ }
83
+
84
+ getHandler (type) {
85
+ return this.handlers[type] || this.handlers.default
86
+ }
87
+ }
88
+
89
+ module.exports = LangChainPlugin
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ function getTokensFromLlmOutput (result) {
4
+ const tokens = {
5
+ input: 0,
6
+ output: 0,
7
+ total: 0
8
+ }
9
+ const { llmOutput } = result
10
+ if (!llmOutput) return tokens
11
+
12
+ const tokenUsage = llmOutput.tokenUsage || llmOutput.usage_metadata || llmOutput.usage_metadata
13
+ if (!tokenUsage) return tokens
14
+
15
+ for (const tokenNames of [['input', 'prompt'], ['output', 'completion'], ['total']]) {
16
+ let token = 0
17
+ for (const tokenName of tokenNames) {
18
+ const underScore = `${tokenName}_tokens`
19
+ const camelCase = `${tokenName}Tokens`
20
+
21
+ token = tokenUsage[underScore] || tokenUsage[camelCase] || token
22
+ }
23
+
24
+ tokens[tokenNames[0]] = token
25
+ }
26
+
27
+ // assign total_tokens again in case it was improperly set the first time, or was not on tokenUsage
28
+ tokens.total = tokens.total || tokens.input + tokens.output
29
+
30
+ return tokens
31
+ }
32
+
33
+ module.exports = {
34
+ getTokensFromLlmOutput
35
+ }
@@ -85,7 +85,7 @@ class MochaPlugin extends CiPlugin {
85
85
  }
86
86
 
87
87
  const relativeCoverageFiles = [...coverageFiles, suiteFile]
88
- .map(filename => getTestSuitePath(filename, this.sourceRoot))
88
+ .map(filename => getTestSuitePath(filename, this.repositoryRoot || this.sourceRoot))
89
89
 
90
90
  const { _traceId, _spanId } = testSuiteSpan.context()
91
91
 
@@ -9,7 +9,6 @@ class MoleculerServerPlugin extends ServerPlugin {
9
9
 
10
10
  start ({ action, ctx, broker }) {
11
11
  const followsFrom = this.tracer.extract('text_map', ctx.meta)
12
-
13
12
  this.startSpan(this.operationName(), {
14
13
  childOf: followsFrom || this.activeSpan,
15
14
  service: this.config.service || this.serviceName(),
@@ -1,61 +1,84 @@
1
1
  'use strict'
2
2
 
3
+ const TTLCache = require('@isaacs/ttlcache')
4
+ const web = require('../plugins/util/web')
3
5
  const log = require('../log')
6
+ const { AUTO_REJECT, USER_REJECT } = require('../../../../ext/priority')
7
+
8
+ const MAX_SIZE = 4096
4
9
 
5
10
  let enabled
6
- let requestSampling
11
+ let sampledRequests
7
12
 
8
- const sampledRequests = new WeakSet()
13
+ class NoopTTLCache {
14
+ clear () { }
15
+ set (key) { return undefined }
16
+ has (key) { return false }
17
+ }
9
18
 
10
19
  function configure ({ apiSecurity }) {
11
20
  enabled = apiSecurity.enabled
12
- setRequestSampling(apiSecurity.requestSampling)
21
+ sampledRequests = apiSecurity.sampleDelay === 0
22
+ ? new NoopTTLCache()
23
+ : new TTLCache({ max: MAX_SIZE, ttl: apiSecurity.sampleDelay * 1000 })
13
24
  }
14
25
 
15
26
  function disable () {
16
27
  enabled = false
28
+ sampledRequests?.clear()
17
29
  }
18
30
 
19
- function setRequestSampling (sampling) {
20
- requestSampling = parseRequestSampling(sampling)
21
- }
31
+ function sampleRequest (req, res, force = false) {
32
+ if (!enabled) return false
22
33
 
23
- function parseRequestSampling (requestSampling) {
24
- let parsed = parseFloat(requestSampling)
34
+ const key = computeKey(req, res)
35
+ if (!key || isSampled(key)) return false
25
36
 
26
- if (isNaN(parsed)) {
27
- log.warn(`Incorrect API Security request sampling value: ${requestSampling}`)
37
+ const rootSpan = web.root(req)
38
+ if (!rootSpan) return false
28
39
 
29
- parsed = 0
30
- } else {
31
- parsed = Math.min(1, Math.max(0, parsed))
40
+ let priority = getSpanPriority(rootSpan)
41
+ if (!priority) {
42
+ rootSpan._prioritySampler?.sample(rootSpan)
43
+ priority = getSpanPriority(rootSpan)
32
44
  }
33
45
 
34
- return parsed
35
- }
36
-
37
- function sampleRequest (req) {
38
- if (!enabled || !requestSampling) {
46
+ if (priority === AUTO_REJECT || priority === USER_REJECT) {
39
47
  return false
40
48
  }
41
49
 
42
- const shouldSample = Math.random() <= requestSampling
43
-
44
- if (shouldSample) {
45
- sampledRequests.add(req)
50
+ if (force) {
51
+ sampledRequests.set(key)
46
52
  }
47
53
 
48
- return shouldSample
54
+ return true
55
+ }
56
+
57
+ function isSampled (key) {
58
+ return sampledRequests.has(key)
59
+ }
60
+
61
+ function computeKey (req, res) {
62
+ const route = web.getContext(req)?.paths?.join('') || ''
63
+ const method = req.method
64
+ const status = res.statusCode
65
+
66
+ if (!method || !status) {
67
+ log.warn('Unsupported groupkey for API security')
68
+ return null
69
+ }
70
+ return method + route + status
49
71
  }
50
72
 
51
- function isSampled (req) {
52
- return sampledRequests.has(req)
73
+ function getSpanPriority (span) {
74
+ const spanContext = span.context?.()
75
+ return spanContext._sampling?.priority
53
76
  }
54
77
 
55
78
  module.exports = {
56
79
  configure,
57
80
  disable,
58
- setRequestSampling,
59
81
  sampleRequest,
60
- isSampled
82
+ isSampled,
83
+ computeKey
61
84
  }
@@ -15,6 +15,7 @@ module.exports = {
15
15
  PATH_TRAVERSAL_ANALYZER: require('./path-traversal-analyzer'),
16
16
  SQL_INJECTION_ANALYZER: require('./sql-injection-analyzer'),
17
17
  SSRF: require('./ssrf-analyzer'),
18
+ TEMPLATE_INJECTION_ANALYZER: require('./template-injection-analyzer'),
18
19
  UNVALIDATED_REDIRECT_ANALYZER: require('./unvalidated-redirect-analyzer'),
19
20
  WEAK_CIPHER_ANALYZER: require('./weak-cipher-analyzer'),
20
21
  WEAK_HASH_ANALYZER: require('./weak-hash-analyzer'),
@@ -6,7 +6,6 @@ const { getNodeModulesPaths } = require('../path-line')
6
6
  const { HEADER_NAME_VALUE_SEPARATOR } = require('../vulnerabilities-formatter/constants')
7
7
  const { getRanges } = require('../taint-tracking/operations')
8
8
  const {
9
- HTTP_REQUEST_COOKIE_NAME,
10
9
  HTTP_REQUEST_COOKIE_VALUE,
11
10
  HTTP_REQUEST_HEADER_VALUE
12
11
  } = require('../taint-tracking/source-types')
@@ -45,13 +44,7 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
45
44
  if (this.isExcludedHeaderName(lowerCasedHeaderName) || typeof value !== 'string') return
46
45
 
47
46
  const ranges = getRanges(iastContext, value)
48
- if (ranges?.length > 0) {
49
- return !(this.isCookieExclusion(lowerCasedHeaderName, ranges) ||
50
- this.isSameHeaderExclusion(lowerCasedHeaderName, ranges) ||
51
- this.isAccessControlAllowExclusion(lowerCasedHeaderName, ranges))
52
- }
53
-
54
- return false
47
+ return ranges?.length > 0 && !this.shouldIgnoreHeader(lowerCasedHeaderName, ranges)
55
48
  }
56
49
 
57
50
  _getEvidence (headerInfo, iastContext) {
@@ -75,28 +68,52 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
75
68
  return EXCLUDED_HEADER_NAMES.includes(name)
76
69
  }
77
70
 
78
- isCookieExclusion (name, ranges) {
79
- if (name === 'set-cookie') {
80
- return ranges
81
- .every(range => range.iinfo.type === HTTP_REQUEST_COOKIE_VALUE || range.iinfo.type === HTTP_REQUEST_COOKIE_NAME)
82
- }
71
+ isAllRangesFromHeader (ranges, headerName) {
72
+ return ranges
73
+ .every(range =>
74
+ range.iinfo.type === HTTP_REQUEST_HEADER_VALUE && range.iinfo.parameterName?.toLowerCase() === headerName
75
+ )
76
+ }
83
77
 
84
- return false
78
+ isAllRangesFromSource (ranges, source) {
79
+ return ranges
80
+ .every(range => range.iinfo.type === source)
85
81
  }
86
82
 
83
+ /**
84
+ * Exclude access-control-allow-*: when the header starts with access-control-allow- and the
85
+ * source of the tainted range is a request header
86
+ */
87
87
  isAccessControlAllowExclusion (name, ranges) {
88
88
  if (name?.startsWith('access-control-allow-')) {
89
- return ranges
90
- .every(range => range.iinfo.type === HTTP_REQUEST_HEADER_VALUE)
89
+ return this.isAllRangesFromSource(ranges, HTTP_REQUEST_HEADER_VALUE)
91
90
  }
92
91
 
93
92
  return false
94
93
  }
95
94
 
95
+ /** Exclude when the header is reflected from the request */
96
96
  isSameHeaderExclusion (name, ranges) {
97
97
  return ranges.length === 1 && name === ranges[0].iinfo.parameterName?.toLowerCase()
98
98
  }
99
99
 
100
+ shouldIgnoreHeader (headerName, ranges) {
101
+ switch (headerName) {
102
+ case 'set-cookie':
103
+ /** Exclude set-cookie header if the source of all the tainted ranges are cookies */
104
+ return this.isAllRangesFromSource(ranges, HTTP_REQUEST_COOKIE_VALUE)
105
+ case 'pragma':
106
+ /** Ignore pragma headers when the source is the cache control header. */
107
+ return this.isAllRangesFromHeader(ranges, 'cache-control')
108
+ case 'transfer-encoding':
109
+ case 'content-encoding':
110
+ /** Ignore transfer and content encoding headers when the source is the accept encoding header. */
111
+ return this.isAllRangesFromHeader(ranges, 'accept-encoding')
112
+ }
113
+
114
+ return this.isAccessControlAllowExclusion(headerName, ranges) || this.isSameHeaderExclusion(headerName, ranges)
115
+ }
116
+
100
117
  _getExcludedPaths () {
101
118
  return EXCLUDED_PATHS
102
119
  }
@@ -0,0 +1,18 @@
1
+ 'use strict'
2
+
3
+ const InjectionAnalyzer = require('./injection-analyzer')
4
+ const { TEMPLATE_INJECTION } = require('../vulnerabilities')
5
+
6
+ class TemplateInjectionAnalyzer extends InjectionAnalyzer {
7
+ constructor () {
8
+ super(TEMPLATE_INJECTION)
9
+ }
10
+
11
+ onConfigure () {
12
+ this.addSub('datadog:handlebars:compile:start', ({ source }) => this.analyze(source))
13
+ this.addSub('datadog:handlebars:register-partial:start', ({ partial }) => this.analyze(partial))
14
+ this.addSub('datadog:pug:compile:start', ({ source }) => this.analyze(source))
15
+ }
16
+ }
17
+
18
+ module.exports = new TemplateInjectionAnalyzer()
@@ -5,13 +5,13 @@ 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')
9
8
  const commandSensitiveAnalyzer = require('./sensitive-analyzers/command-sensitive-analyzer')
10
9
  const hardcodedPasswordAnalyzer = require('./sensitive-analyzers/hardcoded-password-analyzer')
11
10
  const headerSensitiveAnalyzer = require('./sensitive-analyzers/header-sensitive-analyzer')
12
11
  const jsonSensitiveAnalyzer = require('./sensitive-analyzers/json-sensitive-analyzer')
13
12
  const ldapSensitiveAnalyzer = require('./sensitive-analyzers/ldap-sensitive-analyzer')
14
13
  const sqlSensitiveAnalyzer = require('./sensitive-analyzers/sql-sensitive-analyzer')
14
+ const taintedRangeBasedSensitiveAnalyzer = require('./sensitive-analyzers/tainted-range-based-sensitive-analyzer')
15
15
  const urlSensitiveAnalyzer = require('./sensitive-analyzers/url-sensitive-analyzer')
16
16
 
17
17
  const { DEFAULT_IAST_REDACTION_NAME_PATTERN, DEFAULT_IAST_REDACTION_VALUE_PATTERN } = require('./sensitive-regex')
@@ -24,7 +24,8 @@ class SensitiveHandler {
24
24
  this._valuePattern = new RegExp(DEFAULT_IAST_REDACTION_VALUE_PATTERN, 'gmi')
25
25
 
26
26
  this._sensitiveAnalyzers = new Map()
27
- this._sensitiveAnalyzers.set(vulnerabilities.CODE_INJECTION, codeInjectionSensitiveAnalyzer)
27
+ this._sensitiveAnalyzers.set(vulnerabilities.CODE_INJECTION, taintedRangeBasedSensitiveAnalyzer)
28
+ this._sensitiveAnalyzers.set(vulnerabilities.TEMPLATE_INJECTION, taintedRangeBasedSensitiveAnalyzer)
28
29
  this._sensitiveAnalyzers.set(vulnerabilities.COMMAND_INJECTION, commandSensitiveAnalyzer)
29
30
  this._sensitiveAnalyzers.set(vulnerabilities.NOSQL_MONGODB_INJECTION, jsonSensitiveAnalyzer)
30
31
  this._sensitiveAnalyzers.set(vulnerabilities.LDAP_INJECTION, ldapSensitiveAnalyzer)
@@ -13,6 +13,7 @@ module.exports = {
13
13
  PATH_TRAVERSAL: 'PATH_TRAVERSAL',
14
14
  SQL_INJECTION: 'SQL_INJECTION',
15
15
  SSRF: 'SSRF',
16
+ TEMPLATE_INJECTION: 'TEMPLATE_INJECTION',
16
17
  UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
17
18
  WEAK_CIPHER: 'WEAK_CIPHER',
18
19
  WEAK_HASH: 'WEAK_HASH',
@@ -145,10 +145,6 @@ function incomingHttpStartTranslator ({ req, res, abortController }) {
145
145
  persistent[addresses.HTTP_CLIENT_IP] = clientIp
146
146
  }
147
147
 
148
- if (apiSecuritySampler.sampleRequest(req)) {
149
- persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
150
- }
151
-
152
148
  const actions = waf.run({ persistent }, req)
153
149
 
154
150
  handleResults(actions, req, res, rootSpan, abortController)
@@ -172,6 +168,10 @@ function incomingHttpEndTranslator ({ req, res }) {
172
168
  persistent[addresses.HTTP_INCOMING_QUERY] = req.query
173
169
  }
174
170
 
171
+ if (apiSecuritySampler.sampleRequest(req, res, true)) {
172
+ persistent[addresses.WAF_CONTEXT_PROCESSOR] = { 'extract-schema': true }
173
+ }
174
+
175
175
  if (Object.keys(persistent).length) {
176
176
  waf.run({ persistent }, req)
177
177
  }
@@ -228,9 +228,9 @@ function onRequestProcessParams ({ req, res, abortController, params }) {
228
228
  handleResults(results, req, res, rootSpan, abortController)
229
229
  }
230
230
 
231
- function onResponseBody ({ req, body }) {
231
+ function onResponseBody ({ req, res, body }) {
232
232
  if (!body || typeof body !== 'object') return
233
- if (!apiSecuritySampler.isSampled(req)) return
233
+ if (!apiSecuritySampler.sampleRequest(req, res)) return
234
234
 
235
235
  // we don't support blocking at this point, so no results needed
236
236
  waf.run({