@contrast/agent-bundle 5.45.1 → 5.47.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 (189) hide show
  1. package/README.md +1 -1
  2. package/node_modules/@contrast/agent/README.md +1 -1
  3. package/node_modules/@contrast/agent/package.json +12 -12
  4. package/node_modules/@contrast/agentify/package.json +15 -15
  5. package/node_modules/@contrast/architecture-components/package.json +5 -5
  6. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/common.js +1 -1
  7. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/handlers.js +24 -11
  8. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/index.js +6 -4
  9. package/node_modules/@contrast/assess/lib/configuration-analysis/install/apollo-server.js +92 -0
  10. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/express-session.js +2 -2
  11. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/fastify-cookie.js +2 -2
  12. package/node_modules/@contrast/assess/lib/configuration-analysis/install/graphql-yoga.js +90 -0
  13. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/hapi.js +2 -2
  14. package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/koa.js +3 -3
  15. package/node_modules/@contrast/assess/lib/dataflow/propagation/install/string/substring.js +1 -1
  16. package/node_modules/@contrast/assess/lib/dataflow/sources/handler.js +30 -26
  17. package/node_modules/@contrast/assess/lib/dataflow/sources/index.js +2 -0
  18. package/node_modules/@contrast/assess/lib/dataflow/sources/install/fastify-websocket.js +63 -0
  19. package/node_modules/@contrast/assess/lib/dataflow/sources/install/http.js +42 -38
  20. package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/index.js +1 -1
  21. package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-bodyparsers.js +76 -48
  22. package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-multer.js +1 -1
  23. package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-routers.js +2 -2
  24. package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/{koa2.js → koa.js} +3 -3
  25. package/node_modules/@contrast/assess/lib/dataflow/sources/install/socket.io.js +80 -0
  26. package/node_modules/@contrast/assess/lib/get-source-context.js +10 -21
  27. package/node_modules/@contrast/assess/lib/index.d.ts +4 -3
  28. package/node_modules/@contrast/assess/lib/index.js +2 -2
  29. package/node_modules/@contrast/assess/lib/make-source-context.js +5 -10
  30. package/node_modules/@contrast/assess/lib/policy.js +400 -0
  31. package/node_modules/@contrast/assess/lib/response-scanning/handlers/index.js +10 -14
  32. package/node_modules/@contrast/assess/package.json +12 -12
  33. package/node_modules/@contrast/common/lib/constants.d.ts +12 -4
  34. package/node_modules/@contrast/common/lib/constants.js +16 -7
  35. package/node_modules/@contrast/common/lib/types.d.ts +5 -1
  36. package/node_modules/@contrast/common/package.json +1 -1
  37. package/node_modules/@contrast/config/lib/common.js +1 -0
  38. package/node_modules/@contrast/config/lib/options.js +14 -0
  39. package/node_modules/@contrast/config/package.json +3 -3
  40. package/node_modules/@contrast/core/package.json +5 -5
  41. package/node_modules/@contrast/deadzones/package.json +5 -5
  42. package/node_modules/@contrast/dep-hooks/lib/package-finder.d.ts +2 -2
  43. package/node_modules/@contrast/dep-hooks/lib/package-finder.js +3 -2
  44. package/node_modules/@contrast/dep-hooks/package.json +4 -4
  45. package/node_modules/@contrast/esm-hooks/README.md +2 -2
  46. package/node_modules/@contrast/esm-hooks/package.json +6 -6
  47. package/node_modules/@contrast/instrumentation/package.json +5 -5
  48. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/dep.json +149 -149
  49. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/index.js +2 -11
  50. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/utils.js +2 -0
  51. package/node_modules/@contrast/library-analysis/lib/install/library-usage/index.js +3 -1
  52. package/node_modules/@contrast/library-analysis/lib/util.js +0 -2
  53. package/node_modules/@contrast/library-analysis/package.json +4 -4
  54. package/node_modules/@contrast/logger/package.json +3 -3
  55. package/node_modules/@contrast/metrics/package.json +6 -6
  56. package/node_modules/@contrast/patcher/package.json +2 -2
  57. package/node_modules/@contrast/protect/lib/error-handlers/index.js +1 -1
  58. package/node_modules/@contrast/protect/lib/error-handlers/install/{koa2.js → koa.js} +4 -4
  59. package/node_modules/@contrast/protect/lib/index.d.ts +1 -1
  60. package/node_modules/@contrast/protect/lib/input-analysis/handlers.js +1 -12
  61. package/node_modules/@contrast/protect/lib/input-analysis/index.js +2 -3
  62. package/node_modules/@contrast/protect/lib/input-analysis/install/koa-bodyparsers.js +92 -0
  63. package/node_modules/@contrast/protect/lib/input-analysis/install/{koa2.js → koa.js} +5 -5
  64. package/node_modules/@contrast/protect/package.json +11 -11
  65. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/application-activity/translations.js +6 -10
  66. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/routes-observed.js +4 -0
  67. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/index.d.ts +1 -1
  68. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/index.js +1 -1
  69. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.d.ts +1 -1
  70. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.js +22 -9
  71. package/node_modules/@contrast/reporter/lib/reporters/file.js +1 -1
  72. package/node_modules/@contrast/reporter/package.json +6 -6
  73. package/node_modules/@contrast/rewriter/package.json +5 -5
  74. package/node_modules/@contrast/route-coverage/lib/index.d.ts +0 -2
  75. package/node_modules/@contrast/route-coverage/lib/index.js +10 -1
  76. package/node_modules/@contrast/route-coverage/lib/install/express/express5.js +16 -1
  77. package/node_modules/@contrast/route-coverage/lib/install/fastify.js +25 -15
  78. package/node_modules/@contrast/route-coverage/lib/install/graphql.js +6 -1
  79. package/node_modules/@contrast/route-coverage/lib/install/koa.js +1 -1
  80. package/node_modules/@contrast/route-coverage/lib/install/socket.io.js +127 -0
  81. package/node_modules/@contrast/route-coverage/package.json +8 -8
  82. package/node_modules/@contrast/scopes/package.json +5 -5
  83. package/node_modules/@contrast/sec-obs/package.json +9 -9
  84. package/node_modules/@contrast/sources/lib/index.js +65 -22
  85. package/node_modules/@contrast/sources/lib/index.test.js +78 -33
  86. package/node_modules/@contrast/sources/lib/source-info.js +1 -10
  87. package/node_modules/@contrast/sources/package.json +3 -3
  88. package/node_modules/@contrast/telemetry/package.json +5 -5
  89. package/node_modules/@types/node/README.md +1 -1
  90. package/node_modules/@types/node/assert/strict.d.ts +105 -2
  91. package/node_modules/@types/node/assert.d.ts +154 -95
  92. package/node_modules/@types/node/buffer.buffer.d.ts +9 -0
  93. package/node_modules/@types/node/buffer.d.ts +8 -4
  94. package/node_modules/@types/node/child_process.d.ts +65 -42
  95. package/node_modules/@types/node/cluster.d.ts +4 -5
  96. package/node_modules/@types/node/crypto.d.ts +1173 -322
  97. package/node_modules/@types/node/dgram.d.ts +9 -8
  98. package/node_modules/@types/node/diagnostics_channel.d.ts +0 -2
  99. package/node_modules/@types/node/dns.d.ts +1 -1
  100. package/node_modules/@types/node/events.d.ts +80 -34
  101. package/node_modules/@types/node/fs/promises.d.ts +39 -21
  102. package/node_modules/@types/node/fs.d.ts +328 -87
  103. package/node_modules/@types/node/globals.d.ts +2 -0
  104. package/node_modules/@types/node/globals.typedarray.d.ts +19 -0
  105. package/node_modules/@types/node/http.d.ts +94 -30
  106. package/node_modules/@types/node/http2.d.ts +178 -52
  107. package/node_modules/@types/node/https.d.ts +91 -62
  108. package/node_modules/@types/node/index.d.ts +2 -0
  109. package/node_modules/@types/node/inspector.d.ts +24 -0
  110. package/node_modules/@types/node/inspector.generated.d.ts +181 -0
  111. package/node_modules/@types/node/net.d.ts +12 -11
  112. package/node_modules/@types/node/os.d.ts +14 -3
  113. package/node_modules/@types/node/package.json +3 -3
  114. package/node_modules/@types/node/perf_hooks.d.ts +6 -8
  115. package/node_modules/@types/node/process.d.ts +12 -23
  116. package/node_modules/@types/node/readline/promises.d.ts +1 -1
  117. package/node_modules/@types/node/sea.d.ts +9 -0
  118. package/node_modules/@types/node/sqlite.d.ts +119 -10
  119. package/node_modules/@types/node/stream/consumers.d.ts +2 -2
  120. package/node_modules/@types/node/stream/web.d.ts +6 -55
  121. package/node_modules/@types/node/stream.d.ts +38 -23
  122. package/node_modules/@types/node/string_decoder.d.ts +2 -2
  123. package/node_modules/@types/node/test.d.ts +31 -26
  124. package/node_modules/@types/node/tls.d.ts +90 -66
  125. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +10 -2
  126. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +16 -0
  127. package/node_modules/@types/node/ts5.6/index.d.ts +2 -0
  128. package/node_modules/@types/node/ts5.7/index.d.ts +2 -0
  129. package/node_modules/@types/node/url.d.ts +8 -3
  130. package/node_modules/@types/node/util.d.ts +17 -3
  131. package/node_modules/@types/node/v8.d.ts +38 -5
  132. package/node_modules/@types/node/vm.d.ts +169 -88
  133. package/node_modules/@types/node/wasi.d.ts +1 -1
  134. package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
  135. package/node_modules/@types/node/web-globals/events.d.ts +3 -0
  136. package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
  137. package/node_modules/@types/node/worker_threads.d.ts +109 -48
  138. package/node_modules/@types/node/zlib.d.ts +31 -24
  139. package/node_modules/axios/CHANGELOG.md +403 -357
  140. package/node_modules/axios/README.md +80 -49
  141. package/node_modules/axios/dist/axios.js +121 -46
  142. package/node_modules/axios/dist/axios.js.map +1 -1
  143. package/node_modules/axios/dist/axios.min.js +2 -2
  144. package/node_modules/axios/dist/axios.min.js.map +1 -1
  145. package/node_modules/axios/dist/browser/axios.cjs +126 -57
  146. package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
  147. package/node_modules/axios/dist/esm/axios.js +126 -57
  148. package/node_modules/axios/dist/esm/axios.js.map +1 -1
  149. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  150. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  151. package/node_modules/axios/dist/node/axios.cjs +346 -97
  152. package/node_modules/axios/dist/node/axios.cjs.map +1 -1
  153. package/node_modules/axios/index.d.cts +4 -0
  154. package/node_modules/axios/index.d.ts +4 -0
  155. package/node_modules/axios/lib/adapters/adapters.js +85 -40
  156. package/node_modules/axios/lib/adapters/fetch.js +1 -1
  157. package/node_modules/axios/lib/adapters/http.js +220 -42
  158. package/node_modules/axios/lib/core/InterceptorManager.js +1 -1
  159. package/node_modules/axios/lib/core/mergeConfig.js +4 -4
  160. package/node_modules/axios/lib/env/data.js +1 -1
  161. package/node_modules/axios/lib/helpers/HttpStatusCode.js +6 -0
  162. package/node_modules/axios/lib/helpers/bind.js +7 -0
  163. package/node_modules/axios/lib/helpers/cookies.js +24 -13
  164. package/node_modules/axios/package.json +9 -4
  165. package/node_modules/detect-libc/lib/filesystem.js +1 -1
  166. package/node_modules/detect-libc/package.json +3 -1
  167. package/node_modules/node-abi/abi_registry.json +12 -2
  168. package/node_modules/node-abi/package.json +3 -6
  169. package/node_modules/semver/classes/range.js +1 -0
  170. package/node_modules/semver/classes/semver.js +19 -5
  171. package/node_modules/semver/internal/identifiers.js +4 -0
  172. package/node_modules/semver/package.json +3 -3
  173. package/node_modules/undici-types/agent.d.ts +1 -4
  174. package/node_modules/undici-types/client.d.ts +0 -2
  175. package/node_modules/undici-types/diagnostics-channel.d.ts +0 -1
  176. package/node_modules/undici-types/dispatcher.d.ts +0 -6
  177. package/node_modules/undici-types/errors.d.ts +5 -15
  178. package/node_modules/undici-types/eventsource.d.ts +6 -1
  179. package/node_modules/undici-types/h2c-client.d.ts +0 -2
  180. package/node_modules/undici-types/index.d.ts +6 -1
  181. package/node_modules/undici-types/interceptors.d.ts +5 -0
  182. package/node_modules/undici-types/mock-interceptor.d.ts +0 -1
  183. package/node_modules/undici-types/package.json +1 -1
  184. package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  185. package/node_modules/undici-types/webidl.d.ts +82 -21
  186. package/package.json +3 -3
  187. package/node_modules/@contrast/assess/lib/get-policy.js +0 -336
  188. package/node_modules/@contrast/protect/lib/input-analysis/install/koa-body5.js +0 -63
  189. package/node_modules/@contrast/protect/lib/input-analysis/install/koa-bodyparser4.js +0 -64
@@ -10,11 +10,6 @@ type SequenceConverter<T> = (object: unknown, iterable?: IterableIterator<T>) =>
10
10
 
11
11
  type RecordConverter<K extends string, V> = (object: unknown) => Record<K, V>
12
12
 
13
- interface ConvertToIntOpts {
14
- clamp?: boolean
15
- enforceRange?: boolean
16
- }
17
-
18
13
  interface WebidlErrors {
19
14
  /**
20
15
  * @description Instantiate an error
@@ -74,7 +69,7 @@ interface WebidlUtil {
74
69
  V: unknown,
75
70
  bitLength: number,
76
71
  signedness: 'signed' | 'unsigned',
77
- opts?: ConvertToIntOpts
72
+ flags?: number
78
73
  ): number
79
74
 
80
75
  /**
@@ -94,15 +89,17 @@ interface WebidlUtil {
94
89
  * This is only effective in some newer Node.js versions.
95
90
  */
96
91
  markAsUncloneable (V: any): void
92
+
93
+ IsResizableArrayBuffer (V: ArrayBufferLike): boolean
94
+
95
+ HasFlag (flag: number, attributes: number): boolean
97
96
  }
98
97
 
99
98
  interface WebidlConverters {
100
99
  /**
101
100
  * @see https://webidl.spec.whatwg.org/#es-DOMString
102
101
  */
103
- DOMString (V: unknown, prefix: string, argument: string, opts?: {
104
- legacyNullToEmptyString: boolean
105
- }): string
102
+ DOMString (V: unknown, prefix: string, argument: string, flags?: number): string
106
103
 
107
104
  /**
108
105
  * @see https://webidl.spec.whatwg.org/#es-ByteString
@@ -142,39 +139,78 @@ interface WebidlConverters {
142
139
  /**
143
140
  * @see https://webidl.spec.whatwg.org/#es-unsigned-short
144
141
  */
145
- ['unsigned short'] (V: unknown, opts?: ConvertToIntOpts): number
142
+ ['unsigned short'] (V: unknown, flags?: number): number
146
143
 
147
144
  /**
148
145
  * @see https://webidl.spec.whatwg.org/#idl-ArrayBuffer
149
146
  */
150
- ArrayBuffer (V: unknown): ArrayBufferLike
151
- ArrayBuffer (V: unknown, opts: { allowShared: false }): ArrayBuffer
147
+ ArrayBuffer (
148
+ V: unknown,
149
+ prefix: string,
150
+ argument: string,
151
+ options?: { allowResizable: boolean }
152
+ ): ArrayBuffer
153
+
154
+ /**
155
+ * @see https://webidl.spec.whatwg.org/#idl-SharedArrayBuffer
156
+ */
157
+ SharedArrayBuffer (
158
+ V: unknown,
159
+ prefix: string,
160
+ argument: string,
161
+ options?: { allowResizable: boolean }
162
+ ): SharedArrayBuffer
152
163
 
153
164
  /**
154
165
  * @see https://webidl.spec.whatwg.org/#es-buffer-source-types
155
166
  */
156
167
  TypedArray (
157
168
  V: unknown,
158
- TypedArray: NodeJS.TypedArray | ArrayBufferLike
159
- ): NodeJS.TypedArray | ArrayBufferLike
160
- TypedArray (
169
+ T: new () => NodeJS.TypedArray,
170
+ prefix: string,
171
+ argument: string,
172
+ flags?: number
173
+ ): NodeJS.TypedArray
174
+
175
+ /**
176
+ * @see https://webidl.spec.whatwg.org/#es-buffer-source-types
177
+ */
178
+ DataView (
161
179
  V: unknown,
162
- TypedArray: NodeJS.TypedArray | ArrayBufferLike,
163
- opts?: { allowShared: false }
164
- ): NodeJS.TypedArray | ArrayBuffer
180
+ prefix: string,
181
+ argument: string,
182
+ flags?: number
183
+ ): DataView
165
184
 
166
185
  /**
167
186
  * @see https://webidl.spec.whatwg.org/#es-buffer-source-types
168
187
  */
169
- DataView (V: unknown, opts?: { allowShared: boolean }): DataView
188
+ ArrayBufferView (
189
+ V: unknown,
190
+ prefix: string,
191
+ argument: string,
192
+ flags?: number
193
+ ): NodeJS.ArrayBufferView
170
194
 
171
195
  /**
172
196
  * @see https://webidl.spec.whatwg.org/#BufferSource
173
197
  */
174
198
  BufferSource (
175
199
  V: unknown,
176
- opts?: { allowShared: boolean }
177
- ): NodeJS.TypedArray | ArrayBufferLike | DataView
200
+ prefix: string,
201
+ argument: string,
202
+ flags?: number
203
+ ): ArrayBuffer | NodeJS.ArrayBufferView
204
+
205
+ /**
206
+ * @see https://webidl.spec.whatwg.org/#AllowSharedBufferSource
207
+ */
208
+ AllowSharedBufferSource (
209
+ V: unknown,
210
+ prefix: string,
211
+ argument: string,
212
+ flags?: number
213
+ ): ArrayBuffer | SharedArrayBuffer | NodeJS.ArrayBufferView
178
214
 
179
215
  ['sequence<ByteString>']: SequenceConverter<string>
180
216
 
@@ -192,6 +228,13 @@ interface WebidlConverters {
192
228
  */
193
229
  RequestInit (V: unknown): undici.RequestInit
194
230
 
231
+ /**
232
+ * @see https://html.spec.whatwg.org/multipage/webappapis.html#eventhandlernonnull
233
+ */
234
+ EventHandlerNonNull (V: unknown): Function | null
235
+
236
+ WebSocketStreamWrite (V: unknown): ArrayBuffer | NodeJS.TypedArray | string
237
+
195
238
  [Key: string]: (...args: any[]) => unknown
196
239
  }
197
240
 
@@ -210,6 +253,10 @@ interface WebidlIs {
210
253
  AbortSignal: WebidlIsFunction<AbortSignal>
211
254
  MessagePort: WebidlIsFunction<MessagePort>
212
255
  USVString: WebidlIsFunction<string>
256
+ /**
257
+ * @see https://webidl.spec.whatwg.org/#BufferSource
258
+ */
259
+ BufferSource: WebidlIsFunction<ArrayBuffer | NodeJS.TypedArray>
213
260
  }
214
261
 
215
262
  export interface Webidl {
@@ -217,6 +264,7 @@ export interface Webidl {
217
264
  util: WebidlUtil
218
265
  converters: WebidlConverters
219
266
  is: WebidlIs
267
+ attributes: WebIDLExtendedAttributes
220
268
 
221
269
  /**
222
270
  * @description Performs a brand-check on {@param V} to ensure it is a
@@ -278,3 +326,16 @@ export interface Webidl {
278
326
 
279
327
  argumentLengthCheck (args: { length: number }, min: number, context: string): void
280
328
  }
329
+
330
+ interface WebIDLExtendedAttributes {
331
+ /** https://webidl.spec.whatwg.org/#Clamp */
332
+ Clamp: number
333
+ /** https://webidl.spec.whatwg.org/#EnforceRange */
334
+ EnforceRange: number
335
+ /** https://webidl.spec.whatwg.org/#AllowShared */
336
+ AllowShared: number
337
+ /** https://webidl.spec.whatwg.org/#AllowResizable */
338
+ AllowResizable: number
339
+ /** https://webidl.spec.whatwg.org/#LegacyNullToEmptyString */
340
+ LegacyNullToEmptyString: number
341
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/agent-bundle",
3
- "version": "5.45.1",
3
+ "version": "5.47.0",
4
4
  "description": "Contrast Security Node.js Agent bundle with all dependencies included",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,13 +21,13 @@
21
21
  "main": "./lib/index.js",
22
22
  "engines": {
23
23
  "npm": ">=6.13.7 <7 || >= 8.3.1",
24
- "node": ">=18.7.0 <19 || >=20.6.0 <21 || >= 22.5.1 <23 || >= 24.0.1 <25"
24
+ "node": ">=18.7.0 <19 || >=20.9.0 <21 || >= 22.5.1 <23 || >= 24.0.1 <25"
25
25
  },
26
26
  "scripts": {
27
27
  "test": "bash ../scripts/test.sh"
28
28
  },
29
29
  "dependencies": {
30
- "@contrast/agent": "5.45.1"
30
+ "@contrast/agent": "5.47.0"
31
31
  },
32
32
  "bundleDependencies": [
33
33
  "@contrast/agent"
@@ -1,336 +0,0 @@
1
- /*
2
- * Copyright: 2025 Contrast Security, Inc
3
- * Contact: support@contrastsecurity.com
4
- * License: Commercial
5
-
6
- * NOTICE: This Software and the patented inventions embodied within may only be
7
- * used as part of Contrast Security’s commercial offerings. Even though it is
8
- * made available through public repositories, use of this Software is subject to
9
- * the applicable End User Licensing Agreement found at
10
- * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
- * between Contrast Security and the End User. The Software may not be reverse
12
- * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
- * way not consistent with the End User License Agreement.
14
- */
15
-
16
- 'use strict';
17
-
18
- const {
19
- Event,
20
- ExclusionType,
21
- InputType,
22
- Rule,
23
- ResponseScanningRule,
24
- SessionConfigurationRule,
25
- primordials: { ArrayPrototypeJoin, RegExpPrototypeTest }
26
- } = require('@contrast/common');
27
-
28
- const ASSESS_RULES = Object.values({
29
- ...Rule,
30
- ...ResponseScanningRule,
31
- ...SessionConfigurationRule,
32
- });
33
- const BROAD_INPUT_EXCLUSION_TYPES = [
34
- ExclusionType.BODY,
35
- ExclusionType.QUERYSTRING
36
- ];
37
- const NAMED_INPUT_EXCLUSION_TYPES = [
38
- ExclusionType.COOKIE,
39
- ExclusionType.HEADER,
40
- ExclusionType.PARAMETER
41
- ];
42
- const BODY_TYPES = [
43
- InputType.BODY,
44
- InputType.JSON_VALUE,
45
- InputType.JSON_ARRAYED_VALUE,
46
- InputType.MULTIPART_CONTENT_TYPE,
47
- InputType.MULTIPART_FIELD_NAME,
48
- InputType.MULTIPART_NAME,
49
- InputType.MULTIPART_VALUE,
50
- ];
51
- const DISABLED_INPUT_POLICY = { track: false };
52
-
53
- /**
54
- * @param {{
55
- * config: import('@contrast/config').Config,
56
- * logger: import('@contrast/logger').Logger,
57
- * messages: import('@contrast/common').Messages,
58
- * }} core
59
- * @returns {import('@contrast/common').Installable}
60
- */
61
- module.exports = function assess(core) {
62
- const { config, logger, messages } = core;
63
-
64
- const globalPolicy = {
65
- // by default all rules are enabled
66
- enabledRules: new Set(ASSESS_RULES),
67
- exclusionMap: new Map([
68
- [ExclusionType.BODY, []],
69
- [ExclusionType.COOKIE, []],
70
- [ExclusionType.HEADER, []],
71
- [ExclusionType.PARAMETER, []],
72
- [ExclusionType.QUERYSTRING, []],
73
- [ExclusionType.URL, []],
74
- ]),
75
- };
76
-
77
- /**
78
- * Subscribe to settings updates and modify global policy accordingly.
79
- */
80
- messages.on(Event.SERVER_SETTINGS_UPDATE, (msg) => {
81
- if (!config.getEffectiveValue('assess.enable')) return;
82
-
83
- if (msg.assess) {
84
- for (const ruleId of ASSESS_RULES) {
85
- const enable = msg.assess[ruleId]?.enable;
86
- if (enable === true) {
87
- globalPolicy.enabledRules.add(ruleId);
88
- if (ruleId === Rule.NOSQL_INJECTION) globalPolicy.enabledRules.add(Rule.NOSQL_INJECTION_MONGO);
89
- } else if (enable === false) {
90
- globalPolicy.enabledRules.delete(ruleId);
91
- if (ruleId === Rule.NOSQL_INJECTION) globalPolicy.enabledRules.delete(Rule.NOSQL_INJECTION_MONGO);
92
- }
93
- }
94
- logger.info({ enabledRules: Array.from(globalPolicy.enabledRules) }, 'Assess policy enabled rules updated');
95
- }
96
-
97
- if (msg.exclusions) {
98
- const rawDtmList = [
99
- // todo: NODE-3281 input exclusions
100
- ...(msg?.exclusions?.input || []),
101
- ...(msg?.exclusions?.url || []),
102
- ].filter((exclusion) => exclusion?.modes?.includes?.('assess'));
103
-
104
- // reset global exclusion state
105
- for (const type of Object.values(ExclusionType)) {
106
- globalPolicy.exclusionMap.get(type).length = 0;
107
- }
108
-
109
- if (!rawDtmList.length) return;
110
-
111
- for (const dtm of rawDtmList) {
112
- // normalize different dtm types
113
- dtm.type = dtm.type || 'URL';
114
- const { type } = dtm;
115
- const key = ExclusionType[type];
116
- // defensive code against unanticipated DTM values
117
- if (key) {
118
- const Ctor = dtm.type === ExclusionType.URL ? UrlExclusion : InputExclusion;
119
- globalPolicy.exclusionMap.get(dtm.type).push(new Ctor(dtm));
120
- }
121
- }
122
-
123
- logger.info({
124
- exclusions: Object.fromEntries(globalPolicy.exclusionMap)
125
- }, 'Assess exclusions updated (%s total)', rawDtmList.length);
126
- }
127
- });
128
-
129
- /**
130
- * Generates the policy for the current request. We return copy of the global policy
131
- * to avoid inconsistent behavior if policy is updated during request handling. In
132
- * addition, the request policy is altered to account for any URL or Input exclusions.
133
- * @param {string} uriPath
134
- */
135
- return core.assess.getPolicy = function getPolicy({ uriPath } = {}) {
136
- const _enabledRules = new Set(globalPolicy.enabledRules);
137
- const exclusionState = {
138
- // types that can be disabled broadly
139
- [ExclusionType.BODY]: { track: true, excludedRules: new Set() },
140
- [ExclusionType.QUERYSTRING]: { track: true, excludedRules: new Set() },
141
- // other types we check by name. parameter applies to body and query params
142
- [ExclusionType.COOKIE]: [],
143
- [ExclusionType.HEADER]: [],
144
- [ExclusionType.PARAMETER]: [],
145
- };
146
-
147
- // Evaluate URL exclusions.
148
- // If one matches and applies to all rules, we return `null` for the policy value, which
149
- // will disable assess for the request (via getSourceContext()). If specific rules are
150
- // disabled, we remove them from the request policy's set of enabled rules.
151
- for (const urlExclusion of globalPolicy.exclusionMap.get(ExclusionType.URL)) {
152
- if (urlExclusion.matchesUriPath(uriPath)) {
153
- if (!urlExclusion.rules?.size) {
154
- core.logger.debug({
155
- name: urlExclusion.name
156
- }, 'All Assess rules have been disabled by URL exclusion');
157
- return null;
158
- } else {
159
- for (const ruleId of urlExclusion.rules) {
160
- _enabledRules.delete(ruleId);
161
- }
162
- core.logger.debug({
163
- name: urlExclusion.name,
164
- rules: Array.from(urlExclusion.rules),
165
- }, 'Assess rules disabled by URL exclusion');
166
- }
167
- }
168
- }
169
-
170
- // Process input exclusions that apply broadly: BODY, QUERYSTRING
171
- for (const type of BROAD_INPUT_EXCLUSION_TYPES) {
172
- const _policy = exclusionState[type];
173
- for (const exclusion of globalPolicy.exclusionMap.get(type)) {
174
- if (exclusion.matchesUriPath(uriPath)) {
175
- if (exclusion.rules.size) {
176
- for (const ruleId of exclusion.rules) {
177
- _policy.excludedRules.add(ruleId);
178
- }
179
- } else {
180
- _policy.track = false;
181
- _policy.excludedRules.clear();
182
- break;
183
- }
184
- }
185
- }
186
- }
187
- // Filter input exclusions that will be used to get named input
188
- // policies: COOKIE, HEADER, PARAMETER
189
- for (const type of NAMED_INPUT_EXCLUSION_TYPES) {
190
- for (const exclusion of globalPolicy.exclusionMap.get(type)) {
191
- if (exclusion.matchesUriPath(uriPath)) {
192
- exclusionState[type].push(exclusion);
193
- }
194
- }
195
- }
196
-
197
- return {
198
- /**
199
- * Enabled rules filtered by any applicable URL exclusions
200
- */
201
- enabledRules: _enabledRules,
202
- /**
203
- * Used by source handler to get policy information for specific named inputs.
204
- * @param {InputType} inputType
205
- * @param {string} [fieldName]
206
- * @returns {InputPolicy}
207
- */
208
- getInputPolicy(inputType, fieldName) {
209
- let exclusionsByType;
210
- const inputPolicy = { track: true, excludedRules: new Set() };
211
-
212
- const isBody = BODY_TYPES.includes(inputType);
213
-
214
- if (isBody || inputType === InputType.QUERYSTRING) {
215
- // these can be disabled broadly
216
- const _policy = exclusionState[isBody ? ExclusionType.BODY : ExclusionType.QUERYSTRING];
217
- if (!_policy.track) {
218
- return DISABLED_INPUT_POLICY;
219
- }
220
- for (const ruleId of _policy.excludedRules) {
221
- inputPolicy.excludedRules.add(ruleId);
222
- }
223
- exclusionsByType = exclusionState[ExclusionType.PARAMETER];
224
- } else if (inputType === InputType.URL_PARAMETER) {
225
- exclusionsByType = exclusionState[ExclusionType.PARAMETER];
226
- } else if (inputType === InputType.HEADER) {
227
- exclusionsByType = exclusionState[ExclusionType.HEADER];
228
- } else if ([
229
- InputType.COOKIE_NAME,
230
- InputType.COOKIE_VALUE
231
- ].includes(inputType)) {
232
- exclusionsByType = exclusionState[ExclusionType.COOKIE];
233
- }
234
-
235
- if (!exclusionsByType) {
236
- return inputPolicy;
237
- }
238
-
239
- // check input name
240
- for (const exclusion of exclusionsByType) {
241
- if (exclusion.matchesInputName(fieldName)) {
242
- if (exclusion.rules.size) {
243
- for (const ruleId of exclusion.rules) {
244
- inputPolicy.excludedRules.add(ruleId);
245
- }
246
- } else {
247
- return DISABLED_INPUT_POLICY;
248
- }
249
- }
250
- }
251
-
252
- return inputPolicy;
253
- },
254
- };
255
- };
256
- };
257
-
258
- /**
259
- * @typedef InputPolicy
260
- * @property {boolean} track
261
- * @property {Set<Rule>} excludedRules
262
- */
263
-
264
- class UrlExclusion {
265
- constructor(dtm) {
266
- this._urlRegex = null;
267
- this._urls = new Set();
268
- this.name = dtm.name;
269
- this.type = ExclusionType[dtm.type];
270
- this.rules = new Set(dtm.assess_rules);
271
-
272
- if (dtm.urls.length) {
273
- const regexSegments = [];
274
- for (const url of dtm.urls) {
275
- if (shouldBeRegExp(url)) {
276
- regexSegments.push(url);
277
- } else {
278
- this._urls.add(url);
279
- }
280
- }
281
- if (regexSegments.length) {
282
- this._urlRegex = new RegExp(`^${ArrayPrototypeJoin.call(regexSegments, '|')}$`);
283
- }
284
- }
285
- }
286
-
287
- /**
288
- * Checks whether the current URI path matches any of the exclusion's URL values.
289
- * Exclusions that don't match for the current request will not be enabled. The
290
- * interpretation of the DTM is that if its urls list is empty, then that means
291
- * it should match all requestss (can be the case for input exclusions).
292
- * @param {string} uriPath uri to check
293
- * @returns {boolean}
294
- */
295
- matchesUriPath(uriPath) {
296
- return (!this._urlRegex && !this._urls.size) ||
297
- this._urls.has(uriPath) ||
298
- !!this._urlRegex?.test?.(uriPath);
299
- }
300
- }
301
-
302
- class InputExclusion extends UrlExclusion {
303
- constructor(dtm) {
304
- super(dtm);
305
- this._inputNameRegex = null;
306
- this._inputName = null;
307
-
308
- // dtm.name value is null for BODY and QUERYSTRING types
309
- if (dtm.name) {
310
- if (shouldBeRegExp(dtm.name)) {
311
- this._inputNameRegex = new RegExp(`^${dtm.name}$`);
312
- } else {
313
- this._inputName = dtm.name;
314
- }
315
- }
316
- }
317
-
318
- /**
319
- * Checks if the provided name matches the value from the exclusion dtm.
320
- * @param {string} name field name being evaluated
321
- * @returns {boolean}
322
- */
323
- matchesInputName(name) {
324
- // BODY and QUERYSTRING always match since they apply broadly
325
- if (!this._inputName && !this._inputNameRegex) return true;
326
- return this._inputNameRegex ? RegExpPrototypeTest.call(this._inputNameRegex, name) : this._inputName === name;
327
- }
328
- }
329
-
330
- function shouldBeRegExp(str) {
331
- return str.indexOf('*') > 0 ||
332
- str.indexOf('.') > 0 ||
333
- str.indexOf('+') > 0 ||
334
- str.indexOf('?') > 0 ||
335
- str.indexOf('\\') > 0;
336
- }
@@ -1,63 +0,0 @@
1
- /*
2
- * Copyright: 2025 Contrast Security, Inc
3
- * Contact: support@contrastsecurity.com
4
- * License: Commercial
5
-
6
- * NOTICE: This Software and the patented inventions embodied within may only be
7
- * used as part of Contrast Security’s commercial offerings. Even though it is
8
- * made available through public repositories, use of this Software is subject to
9
- * the applicable End User Licensing Agreement found at
10
- * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
- * between Contrast Security and the End User. The Software may not be reverse
12
- * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
- * way not consistent with the End User License Agreement.
14
- */
15
-
16
- 'use strict';
17
-
18
- const { patchType } = require('../constants');
19
-
20
- module.exports = (core) => {
21
- const {
22
- depHooks,
23
- patcher,
24
- protect,
25
- protect: { inputAnalysis },
26
- } = core;
27
-
28
- // Patch `koa-body` package
29
- function install() {
30
- depHooks.resolve({ name: 'koa-body', version: '<7' }, (koaBody) => patcher.patch(koaBody, {
31
- name: 'koa-body',
32
- patchType,
33
- post(data) {
34
- data.result = patcher.patch(data.result, {
35
- name: 'koa-body',
36
- patchType,
37
- pre(data) {
38
- const [ctx, origNext] = data.args;
39
-
40
- async function contrastNext(origErr) {
41
- const sourceContext = protect.getSourceContext();
42
-
43
- if (sourceContext && ctx.request.body && Object.keys(ctx.request.body).length) {
44
- sourceContext.parsedBody = ctx.request.body;
45
- inputAnalysis.handleParsedBody(sourceContext, ctx.request.body);
46
- }
47
-
48
- await origNext(origErr);
49
- }
50
-
51
- data.args[1] = contrastNext;
52
- }
53
- });
54
- }
55
- }));
56
- }
57
-
58
- const koaBody5Instrumentation = inputAnalysis.koaBody5Instrumentation = {
59
- install
60
- };
61
-
62
- return koaBody5Instrumentation;
63
- };
@@ -1,64 +0,0 @@
1
- /*
2
- * Copyright: 2025 Contrast Security, Inc
3
- * Contact: support@contrastsecurity.com
4
- * License: Commercial
5
-
6
- * NOTICE: This Software and the patented inventions embodied within may only be
7
- * used as part of Contrast Security’s commercial offerings. Even though it is
8
- * made available through public repositories, use of this Software is subject to
9
- * the applicable End User Licensing Agreement found at
10
- * https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
- * between Contrast Security and the End User. The Software may not be reverse
12
- * engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
- * way not consistent with the End User License Agreement.
14
- */
15
-
16
- 'use strict';
17
-
18
- const { patchType } = require('../constants');
19
-
20
- module.exports = (core) => {
21
- const {
22
- depHooks,
23
- patcher,
24
- protect,
25
- protect: { inputAnalysis },
26
- } = core;
27
-
28
- // Patch `koa-bodyparser` package
29
- function install() {
30
- depHooks.resolve({ name: 'koa-bodyparser', version: '<5' }, (koaBodyparser) => patcher.patch(koaBodyparser, {
31
- name: 'koa-bodyparser',
32
- patchType,
33
- post(data) {
34
- data.result = patcher.patch(data.result, {
35
- name: 'koa-bodyparser',
36
- patchType,
37
- pre(data) {
38
- const [ctx, origNext] = data.args;
39
-
40
- async function contrastNext(origErr) {
41
- const sourceContext = protect.getSourceContext();
42
-
43
-
44
- if (sourceContext && ctx.request.body && Object.keys(ctx.request.body).length) {
45
- sourceContext.parsedBody = ctx.request.body;
46
- inputAnalysis.handleParsedBody(sourceContext, ctx.request.body);
47
- }
48
-
49
- await origNext(origErr);
50
- }
51
-
52
- data.args[1] = contrastNext;
53
- }
54
- });
55
- }
56
- }));
57
- }
58
-
59
- const koaBodyparser4Instrumentation = inputAnalysis.koaBodyparser4Instrumentation = {
60
- install
61
- };
62
-
63
- return koaBodyparser4Instrumentation;
64
- };