@newrelic/security-agent 2.0.0 → 2.1.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 (35) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/THIRD_PARTY_NOTICES.md +36 -6
  3. package/lib/instrumentation-security/core/request-manager.js +37 -7
  4. package/lib/instrumentation-security/core/sec-utils.js +5 -5
  5. package/lib/instrumentation-security/hooks/director/nr-director.js +6 -6
  6. package/lib/instrumentation-security/hooks/express/nr-express.js +11 -8
  7. package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +6 -6
  8. package/lib/instrumentation-security/hooks/fs/nr-fs.js +6 -27
  9. package/lib/instrumentation-security/hooks/grpc-js/nr-grpc.js +4 -4
  10. package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +7 -7
  11. package/lib/instrumentation-security/hooks/http/nr-http.js +15 -9
  12. package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +5 -5
  13. package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +4 -0
  14. package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +4 -0
  15. package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +4 -0
  16. package/lib/instrumentation-security/hooks/native/nr-childProcess.js +4 -0
  17. package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +4 -0
  18. package/lib/instrumentation-security/hooks/restify/nr-restify.js +7 -7
  19. package/lib/instrumentation-security/hooks/undici/nr-undici.js +4 -0
  20. package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +4 -0
  21. package/lib/nr-security-agent/index.js +38 -5
  22. package/lib/nr-security-agent/lib/core/Auth-headers.js +19 -0
  23. package/lib/nr-security-agent/lib/core/ExceptionReporting.js +1 -0
  24. package/lib/nr-security-agent/lib/core/agent.js +3 -0
  25. package/lib/nr-security-agent/lib/core/commonUtils.js +132 -4
  26. package/lib/nr-security-agent/lib/core/connections/websocket/response/IASTUtils.js +28 -2
  27. package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +36 -4
  28. package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +5 -1
  29. package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +7 -4
  30. package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +17 -2
  31. package/lib/nr-security-agent/lib/core/health-check.js +6 -1
  32. package/lib/nr-security-agent/lib/core/sec-util.js +5 -1
  33. package/lib/nr-security-agent/lib/core/websocket-client.js +31 -8
  34. package/lib/nr-security-api/index.js +47 -15
  35. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### v2.1.0 (2024-11-05)
2
+ #### Features
3
+ * IAST support for CI/CD
4
+ * Support for IAST schedule, delay and ignore scan categories
5
+ #### Bug fixes
6
+ * Added default values for scan_schedule, scan_controllers and exclude_from_iast_scan config
7
+ * Fix for security home placeholder replacement in fuzz requests
8
+ * Handling to not resolve file path in fs module instrumentation
9
+ * Fix for batch size and condition of iast-data-request sending
10
+ #### Miscellaneous chores
11
+ * Added requestURI field in http request for application-runtime-error
12
+ * Updated instrumented to get the transaction directly instead of from the active segment
13
+
1
14
  ### v2.0.0 (2024-09-20)
2
15
  ### ⚠ BREAKING CHANGES
3
16
  * Dropped support for Node.js v16
@@ -17,6 +17,7 @@ code, the source code can be found at [https://github.com/newrelic/csec-node-age
17
17
  * [axios](#axios)
18
18
  * [check-disk-space](#check-disk-space)
19
19
  * [content-type](#content-type)
20
+ * [cron](#cron)
20
21
  * [fast-safe-stringify](#fast-safe-stringify)
21
22
  * [find-package-json](#find-package-json)
22
23
  * [hash.js](#hashjs)
@@ -150,6 +151,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
150
151
 
151
152
  ```
152
153
 
154
+ ### cron
155
+
156
+ This product includes source derived from [cron](https://github.com/kelektiv/node-cron) ([v3.1.7](https://github.com/kelektiv/node-cron/tree/v3.1.7)), distributed under the [MIT License](https://github.com/kelektiv/node-cron/blob/v3.1.7/LICENSE):
157
+
158
+ ```
159
+ The MIT License (MIT)
160
+ Copyright © 2017 Nicholas Campbell <nicholas.j.campbell@gmail.com>
161
+
162
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
163
+
164
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
165
+
166
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
167
+
168
+ ```
169
+
153
170
  ### fast-safe-stringify
154
171
 
155
172
  This product includes source derived from [fast-safe-stringify](https://github.com/davidmarkclements/fast-safe-stringify) ([v2.1.1](https://github.com/davidmarkclements/fast-safe-stringify/tree/v2.1.1)), distributed under the [MIT License](https://github.com/davidmarkclements/fast-safe-stringify/blob/v2.1.1/LICENSE):
@@ -242,18 +259,31 @@ THE SOFTWARE.
242
259
 
243
260
  ### https-proxy-agent
244
261
 
245
- This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/node-https-proxy-agent) ([v5.0.1](https://github.com/TooTallNate/node-https-proxy-agent/tree/v5.0.1)), distributed under the [MIT License](https://github.com/TooTallNate/node-https-proxy-agent/blob/v5.0.1/README.md):
262
+ This product includes source derived from [https-proxy-agent](https://github.com/TooTallNate/proxy-agents) ([v7.0.4](https://github.com/TooTallNate/proxy-agents/tree/v7.0.4)), distributed under the [MIT License](https://github.com/TooTallNate/proxy-agents/blob/v7.0.4/LICENSE):
246
263
 
247
264
  ```
248
- MIT License
265
+ (The MIT License)
249
266
 
250
- Copyright (c) <year> <copyright holders>
267
+ Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>
251
268
 
252
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
269
+ Permission is hereby granted, free of charge, to any person obtaining
270
+ a copy of this software and associated documentation files (the
271
+ 'Software'), to deal in the Software without restriction, including
272
+ without limitation the rights to use, copy, modify, merge, publish,
273
+ distribute, sublicense, and/or sell copies of the Software, and to
274
+ permit persons to whom the Software is furnished to do so, subject to
275
+ the following conditions:
253
276
 
254
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
277
+ The above copyright notice and this permission notice shall be
278
+ included in all copies or substantial portions of the Software.
255
279
 
256
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
280
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
281
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
282
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
283
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
284
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
285
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
286
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
257
287
  ```
258
288
 
259
289
  ### is-invalid-path
@@ -4,6 +4,10 @@
4
4
  */
5
5
 
6
6
  const requestMap = new Map();
7
+ const API = require("../../nr-security-api");
8
+ const NRAgent = API.getNRAgent();
9
+ const logger = API.getLogger();
10
+ const regexPatterns = NRAgent && NRAgent.config.security.exclude_from_iast_scan.api
7
11
 
8
12
  /**
9
13
  * Utility to get request by transaction Id
@@ -20,7 +24,33 @@ function getRequestFromId(id) {
20
24
  * @param {*} requestData
21
25
  */
22
26
  function setRequest(id, requestData) {
27
+
23
28
  requestMap.set(id, requestData);
29
+ try {
30
+ const stringToMatch = requestData.url;
31
+ // const filteredString = stringToMatch.split('?')[0];
32
+ const filteredString = stringToMatch;
33
+ let isRegexMatchestoURL = false;
34
+ for (let index = 0; index < regexPatterns.length; index++) {
35
+ const regex = new RegExp(regexPatterns[index], 'gm');
36
+ const matchResult = filteredString.match(regex);
37
+ if (matchResult && matchResult.length > 0) {
38
+ const data = matchResult[0];
39
+ if (filteredString === data) {
40
+ isRegexMatchestoURL = true;
41
+ }
42
+ }
43
+ }
44
+ if (isRegexMatchestoURL) {
45
+ requestMap.delete(id);
46
+ if (API.getSecAgent().status.getStatus() !== 'disabled') {
47
+ logger.debug("Excluding URL %s from IAST processing due to ignore API setting", filteredString);
48
+ }
49
+ }
50
+ } catch (error) {
51
+ logger.debug("Error while processing API regex for restriction", error);
52
+ }
53
+
24
54
  }
25
55
 
26
56
  /**
@@ -29,9 +59,9 @@ function setRequest(id, requestData) {
29
59
  * @returns
30
60
  */
31
61
  function getRequest(shim) {
32
- const segment = shim.getActiveSegment();
33
- if (segment) {
34
- const transactionId = segment.transaction.id;
62
+ const transaction = shim.tracer.getTransaction();
63
+ if (transaction) {
64
+ const transactionId = transaction.id;
35
65
  return getRequestFromId(transactionId);
36
66
  }
37
67
  else if (shim.agent.getLinkingMetadata()) {
@@ -49,9 +79,9 @@ function getRequest(shim) {
49
79
  * @param {*} data
50
80
  */
51
81
  function updateRequestBody(shim, data, isTruncated) {
52
- const segment = shim.getActiveSegment();
53
- if (segment) {
54
- const transactionId = segment.transaction.id;
82
+ const transaction = shim.tracer.getTransaction();
83
+ if (transaction) {
84
+ const transactionId = transaction.id;
55
85
  const requestData = getRequestFromId(transactionId);
56
86
  if (requestData) {
57
87
  requestData.body = data;
@@ -95,4 +125,4 @@ module.exports = {
95
125
  updateRequestBody,
96
126
  gcRequestMap,
97
127
  requestMap
98
- }
128
+ }
@@ -172,15 +172,15 @@ function createPathIfNotExist(dir) {
172
172
  function addRequestData(shim, request) {
173
173
  try {
174
174
  const data = Object.assign({});
175
- const segment = shim.getActiveSegment();
176
- if (segment && segment.transaction) {
175
+ const transaction = shim.tracer.getTransaction();
176
+ if (transaction) {
177
177
  data.protocol = (request.connection && request.connection.encrypted) ? 'https' : 'http';
178
178
  data.body = null;
179
179
  data.headers = request.headers;
180
180
  data.url = request.url;
181
181
  data.method = request.method;
182
182
  data.httpVersion = request.httpVersion;
183
- data.serverPort = segment.transaction.port;
183
+ data.serverPort = transaction.port;
184
184
  data.contextPath = '/';
185
185
  const queryObject = URL.parse(request.url, true).query;
186
186
  data.parameterMap = {};
@@ -195,7 +195,7 @@ function addRequestData(shim, request) {
195
195
  }
196
196
  data.clientIP = requestIp.getClientIp(request);
197
197
  data.dataTruncated = false;
198
- const transactionId = segment.transaction.id;
198
+ const transactionId = transaction.id;
199
199
  const storedRequest = requestManager.getRequestFromId(transactionId);
200
200
  if (storedRequest && storedRequest.uri) {
201
201
  data.uri = storedRequest.uri;
@@ -263,4 +263,4 @@ module.exports = {
263
263
  addRequestData,
264
264
  decryptData,
265
265
  hashVerifier
266
- }
266
+ }
@@ -71,15 +71,15 @@ module.exports = function initialize(shim, director) {
71
71
  * @param {*} params
72
72
  */
73
73
  function extractParams(shim, params) {
74
- const segment = shim.getActiveSegment();
75
- if (segment && segment.transaction) {
76
- let request = requestManager.getRequestFromId(segment.transaction.id);
74
+ const transaction = shim.tracer.getTransaction();
75
+ if (transaction) {
76
+ let request = requestManager.getRequestFromId(transaction.id);
77
77
  if (params && request) {
78
78
  Object.keys(params).forEach(function (key) {
79
79
  if (params[key]) {
80
80
  if (!request.parameterMap[key]) {
81
81
  request.parameterMap[key] = new Array(params[key].toString());
82
- requestManager.setRequest(segment.transaction.id, request);
82
+ requestManager.setRequest(transaction.id, request);
83
83
  }
84
84
  }
85
85
  });
@@ -91,8 +91,8 @@ function extractParams(shim, params) {
91
91
  if (uri.includes(param)) {
92
92
  uri = lodash.replace(uri, param, ':param_input');
93
93
  request.uri = uri;
94
- requestManager.setRequest(segment.transaction.id, request);
94
+ requestManager.setRequest(transaction.id, request);
95
95
  }
96
96
  }
97
97
  }
98
- }
98
+ }
@@ -31,8 +31,11 @@ module.exports = function initialize(shim, express) {
31
31
  if (express.Router.use) {
32
32
  wrapExpress4(shim, express)
33
33
  }
34
- expressFileHook(shim, express && express.response, 'download')
35
- expressFileHook(shim, express && express.response, 'sendFile')
34
+ if(API && API.getNRAgent() && !API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.invalid_file_access){
35
+ expressFileHook(shim, express && express.response, 'download')
36
+ expressFileHook(shim, express && express.response, 'sendFile')
37
+ }
38
+
36
39
  }
37
40
 
38
41
  /**
@@ -82,15 +85,15 @@ function extractParams(shim, req) {
82
85
  if (!requestManager.getRequest(shim)) {
83
86
  secUtils.addRequestData(shim, req);
84
87
  }
85
- const segment = shim.getActiveSegment();
86
- if (segment && segment.transaction) {
87
- let request = requestManager.getRequestFromId(segment.transaction.id);
88
+ const transaction = shim.tracer.getTransaction();
89
+ if (transaction) {
90
+ let request = requestManager.getRequestFromId(transaction.id);
88
91
  if (req.params && request) {
89
92
  Object.keys(req.params).forEach(function (key) {
90
93
  if (req.params[key]) {
91
94
  if (!request.parameterMap[key]) {
92
95
  request.parameterMap[key] = new Array(req.params[key].toString());
93
- requestManager.setRequest(segment.transaction.id, request);
96
+ requestManager.setRequest(transaction.id, request);
94
97
  }
95
98
  }
96
99
  });
@@ -100,14 +103,14 @@ function extractParams(shim, req) {
100
103
  if (req.query[key]) {
101
104
  if (!request.parameterMap[key]) {
102
105
  request.parameterMap[key] = new Array(req.query[key].toString());
103
- requestManager.setRequest(segment.transaction.id, request);
106
+ requestManager.setRequest(transaction.id, request);
104
107
  }
105
108
  }
106
109
  });
107
110
  }
108
111
  if (req.route && req.route.path && request) {
109
112
  request.uri = req.route.path;
110
- requestManager.setRequest(segment.transaction.id, request);
113
+ requestManager.setRequest(transaction.id, request);
111
114
  }
112
115
  }
113
116
  }
@@ -121,15 +121,15 @@ function extractParams(shim, req) {
121
121
  try {
122
122
  const reqURL = req.url || req.raw.url;
123
123
  const parsedURI = url.parse(reqURL).pathname;
124
- const segment = shim.getActiveSegment();
125
- if (segment && segment.transaction) {
126
- let request = requestManager.getRequestFromId(segment.transaction.id);
124
+ const transaction = shim.tracer.getTransaction();
125
+ if (transaction) {
126
+ let request = requestManager.getRequestFromId(transaction.id);
127
127
  if (req.params && segment && request) {
128
128
  Object.keys(req.params).forEach(function (key) {
129
129
  if (req.params[key]) {
130
130
  if (!request.parameterMap[key]) {
131
131
  request.parameterMap[key] = new Array(req.params[key].toString());
132
- requestManager.setRequest(segment.transaction.id, request);
132
+ requestManager.setRequest(transaction.id, request);
133
133
  }
134
134
  }
135
135
  });
@@ -139,7 +139,7 @@ function extractParams(shim, req) {
139
139
  if (req.query[key]) {
140
140
  if (!request.parameterMap[key]) {
141
141
  request.parameterMap[key] = new Array(req.query[key].toString());
142
- requestManager.setRequest(segment.transaction.id, request);
142
+ requestManager.setRequest(transaction.id, request);
143
143
  }
144
144
  }
145
145
  });
@@ -147,7 +147,7 @@ function extractParams(shim, req) {
147
147
  let method = request.method.toUpperCase();
148
148
  if (parsedURI && request && requestManager.requestMap[method + ATTHERATE + parsedURI]) {
149
149
  request.uri = parsedURI;
150
- requestManager.setRequest(segment.transaction.id, request);
150
+ requestManager.setRequest(transaction.id, request);
151
151
  }
152
152
  }
153
153
  } catch (error) {
@@ -94,8 +94,10 @@ const promiseFunctionProbableToFI = [
94
94
  * @param {*} moduleName
95
95
  */
96
96
  function initialize(shim, mod, moduleName) {
97
-
98
-
97
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.invalid_file_access){
98
+ logger.warn('invalid_file_access detection is disabled');
99
+ return;
100
+ }
99
101
  logger.info(`Instrumenting ${moduleName}`);
100
102
  requireHook.initialize(shim)
101
103
  const binding = process.binding("fs");
@@ -142,9 +144,8 @@ function openHook(shim, mod, moduleName) {
142
144
  parameters[0] = API.getSecAgent().applicationInfo.serverInfo.deployedApplications[0].deployedPath + SLASH + parameters[0];
143
145
  } else if (parameters[0].startsWith(SLASHDOTDOT)) {
144
146
  parameters[0] = API.getSecAgent().applicationInfo.serverInfo.deployedApplications[0].deployedPath + parameters[0];
145
- } else {
146
- parameters[0] = path.resolve(parameters[0]);
147
- }
147
+ }
148
+
148
149
  } catch (error) {
149
150
 
150
151
  }
@@ -188,11 +189,6 @@ function probableToFAHooks(shim, mod, moduleName) {
188
189
  const request = requestManager.getRequest(shim);
189
190
  if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
190
191
  const traceObject = secUtils.getTraceObject(shim);
191
- try {
192
- parameters[0] = path.resolve(parameters[0]);
193
- } catch (error) {
194
-
195
- }
196
192
  let absoluteParameters = [parameters[0]];
197
193
  const secMetadata = securityMetaData.getSecurityMetaData(request, absoluteParameters, traceObject, secUtils.getExecutionId(), EVENT_TYPE.FILE_OPERATION, EVENT_CATEGORY.FILE)
198
194
  this.secEvent = API.generateSecEvent(secMetadata);
@@ -228,12 +224,6 @@ function probableToFIHooks(shim, mod, moduleName) {
228
224
  const request = requestManager.getRequest(shim);
229
225
  if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
230
226
  const traceObject = secUtils.getTraceObject(shim);
231
- try {
232
- parameters[0] = path.resolve(parameters[0]);
233
- parameters[1] = path.resolve(parameters[1]);
234
- } catch (error) {
235
-
236
- }
237
227
  let absoluteParameters = [parameters[0]];
238
228
  if (fun === COPY_FILE || fun === RENAME) {
239
229
  const secMetadata = securityMetaData.getSecurityMetaData(request, parameters[1], traceObject, secUtils.getExecutionId(), getCase(arguments[1]), EVENT_CATEGORY.FILE)
@@ -271,11 +261,6 @@ function probablePromiseToFAHooks(shim, mod, moduleName) {
271
261
  const request = requestManager.getRequest(shim);
272
262
  if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
273
263
  const traceObject = secUtils.getTraceObject(shim);
274
- try {
275
- parameters[0] = path.resolve(parameters[0]);
276
- } catch (error) {
277
-
278
- }
279
264
  let absoluteParameters = [parameters[0]];
280
265
  const secMetadata = securityMetaData.getSecurityMetaData(request, absoluteParameters, traceObject, secUtils.getExecutionId(), EVENT_TYPE.FILE_OPERATION, EVENT_CATEGORY.FILE)
281
266
  this.secEvent = API.generateSecEvent(secMetadata);
@@ -304,12 +289,6 @@ function probablePromiseToFIHooks(shim, mod, moduleName) {
304
289
  const request = requestManager.getRequest(shim);
305
290
  if (request && typeof arguments[0] === STRING && !lodash.isEmpty(arguments[0])) {
306
291
  const traceObject = secUtils.getTraceObject(shim);
307
- try {
308
- parameters[0] = path.resolve(parameters[0]);
309
- parameters[1] = path.resolve(parameters[1]);
310
- } catch (error) {
311
-
312
- }
313
292
  let absoluteParameters = [parameters[0]];
314
293
  if (fun === COPY_FILE || fun === RENAME) {
315
294
  const secMetadata = securityMetaData.getSecurityMetaData(request, parameters[1], traceObject, secUtils.getExecutionId(), getCase(arguments[1]), EVENT_CATEGORY.FILE)
@@ -282,8 +282,8 @@ function wrapCallback(shim, mod, method) {
282
282
  function addRequestData(shim, type, path, args) {
283
283
  const data = Object.assign({});
284
284
  try {
285
- const segment = shim.getActiveSegment();
286
- if (segment && segment.transaction) {
285
+ const transaction = shim.tracer.getTransaction();
286
+ if (transaction) {
287
287
  data.method = path;
288
288
  data.url = path;
289
289
  data.uri = path;
@@ -298,7 +298,7 @@ function addRequestData(shim, type, path, args) {
298
298
  data.isGrpc = true;
299
299
  data.body = JSON.stringify(args.request);
300
300
  data.serverPort = shim.serverPort;
301
- const transactionId = segment.transaction.id;
301
+ const transactionId = transaction.id;
302
302
  requestManager.setRequest(transactionId, data);
303
303
  }
304
304
  } catch (error) {
@@ -339,4 +339,4 @@ function iterateNestedObjectForServiceLookup(result, serviceObject) {
339
339
  } catch (error) {
340
340
  logger.error("Error while getting service definition", error);
341
341
  }
342
- }
342
+ }
@@ -101,15 +101,15 @@ function handlerWrapper(shim, mod) {
101
101
  * @param {*} req
102
102
  */
103
103
  function extractParams(shim, req) {
104
- const segment = shim.getActiveSegment();
105
- if (segment && segment.transaction) {
106
- let request = requestManager.getRequestFromId(segment.transaction.id);
104
+ const transaction = shim.tracer.getTransaction();
105
+ if (transaction) {
106
+ let request = requestManager.getRequestFromId(transaction.id);
107
107
  if (req.params && request) {
108
108
  Object.keys(req.params).forEach(function (key) {
109
109
  if (req.params[key]) {
110
110
  if (!request.parameterMap[key]) {
111
111
  request.parameterMap[key] = new Array(req.params[key].toString());
112
- requestManager.setRequest(segment.transaction.id, request);
112
+ requestManager.setRequest(transaction.id, request);
113
113
  }
114
114
  }
115
115
  });
@@ -119,14 +119,14 @@ function extractParams(shim, req) {
119
119
  if (req.query[key]) {
120
120
  if (!request.parameterMap[key]) {
121
121
  request.parameterMap[key] = new Array(req.query[key].toString());
122
- requestManager.setRequest(segment.transaction.id, request);
122
+ requestManager.setRequest(transaction.id, request);
123
123
  }
124
124
  }
125
125
  });
126
126
  }
127
127
  if (req.route && req.route.path && request) {
128
128
  request.uri = req.route.path;
129
- requestManager.setRequest(segment.transaction.id, request);
129
+ requestManager.setRequest(transaction.id, request);
130
130
  }
131
131
  }
132
- }
132
+ }
@@ -34,7 +34,8 @@ const semver = require('semver');
34
34
  const ExceptionReporting = require('../../../nr-security-agent/lib/core/ExceptionReporting');
35
35
 
36
36
  const CSEC_SEP = ':IAST:';
37
- const find = '{{NR_CSEC_VALIDATOR_HOME_TMP}}';
37
+ const sep = require('path').sep;
38
+ const find = `${sep}{{NR_CSEC_VALIDATOR_HOME_TMP}}`;
38
39
  const CSEC_HOME_TMP_CONST = new RegExp(find, 'g');
39
40
  let CSEC_HOME = NRAgent && NRAgent.config.newrelic_home ? NRAgent.config.newrelic_home : NRAgent && NRAgent.config.logging.filepath ? path.dirname(NRAgent.config.logging.filepath) : require('path').join(process.cwd());
40
41
  const CSEC_HOME_TMP = `${CSEC_HOME}/nr-security-home/tmp/language-agent/${process.env.applicationUUID}`
@@ -91,6 +92,10 @@ function setupRequestMapCleanup() {
91
92
  * @param {*} moduleName
92
93
  */
93
94
  function outboundHook(shim, mod, method, moduleName) {
95
+ if (API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.ssrf) {
96
+ logger.warn('ssrf detection is disabled');
97
+ return;
98
+ }
94
99
  logger.debug(`Instrumenting ${moduleName}.${method}`);
95
100
  shim.wrap(mod, method, function makeRequestWrapper(shim, fn) {
96
101
  if (!shim.isFunction(fn)) {
@@ -175,7 +180,7 @@ function parseFuzzheaders(requestData, transactionId) {
175
180
  if (additionalData.length >= 8) {
176
181
  let encryptedData = additionalData[6].trim();
177
182
  let hashVerifier = additionalData[7].trim();
178
-
183
+
179
184
  if (lodash.isEmpty(encryptedData) || lodash.isEmpty(hashVerifier)) {
180
185
  return;
181
186
  }
@@ -189,6 +194,7 @@ function parseFuzzheaders(requestData, transactionId) {
189
194
  logger.debug("fliesTocreate:", filesToCreate);
190
195
  for (let i = 0; i < filesToCreate.length; i++) {
191
196
  let file = filesToCreate[i].trim();
197
+ file = decodeURIComponent(file);
192
198
  file = file.replace(CSEC_HOME_TMP_CONST, CSEC_HOME_TMP);
193
199
  file = path.resolve(file);
194
200
  const parentDir = path.dirname(file);
@@ -227,15 +233,15 @@ function parseFuzzheaders(requestData, transactionId) {
227
233
  function addRequestData(shim, request) {
228
234
  try {
229
235
  const data = Object.assign({});
230
- const segment = shim.getActiveSegment();
231
- if (segment && segment.transaction) {
236
+ const transaction = shim.tracer.getTransaction();
237
+ if (transaction) {
232
238
  data.protocol = (request.connection && request.connection.encrypted) ? 'https' : 'http';
233
239
  data.body = null;
234
240
  data.headers = request.headers;
235
241
  data.url = request.url;
236
242
  data.method = request.method;
237
243
  data.httpVersion = request.httpVersion;
238
- data.serverPort = segment.transaction.port;
244
+ data.serverPort = transaction.port;
239
245
  data.contextPath = '/';
240
246
  const queryObject = URL.parse(request.url, true).query;
241
247
  data.parameterMap = {};
@@ -250,7 +256,7 @@ function addRequestData(shim, request) {
250
256
  }
251
257
  data.clientIP = requestIp.getClientIp(request);
252
258
  data.dataTruncated = false;
253
- const transactionId = segment.transaction.id;
259
+ const transactionId = transaction.id;
254
260
  const storedRequest = requestManager.getRequestFromId(transactionId);
255
261
  lastTransactionId = transactionId;
256
262
  if (storedRequest && storedRequest.uri) {
@@ -290,7 +296,7 @@ function emitHook(shim, mod, moduleName) {
290
296
  const resp = arguments[2];
291
297
 
292
298
  if (arguments[0] == 'request') {
293
- if (NRAgent && NRAgent.config.security.detection.rxss.enabled) {
299
+ if (NRAgent && !NRAgent.config.security.exclude_from_iast_scan.iast_detection_category.rxss && NRAgent.config.security.detection.rxss.enabled) {
294
300
  responseHook(resp, req, shim);
295
301
  }
296
302
 
@@ -362,10 +368,10 @@ function onDataHook(shim, mod) {
362
368
  return function onDataWrapper() {
363
369
  const chunk = arguments[0];
364
370
  const chunkType = typeof chunk;
365
- segment = shim.getActiveSegment()
371
+ const transaction = shim.tracer.getTransaction();
366
372
  if (chunkType === STRING_TYPE || chunkType === ARRAY_TYPE || chunkType === BUFFER_TYPE || chunkType === UINT8ARRAY_TYPE || chunkType === OBJECT_TYPE) {
367
373
  let data = chunk.toString();
368
- const transactionId = segment.transaction.id;
374
+ const transactionId = transaction.id;
369
375
  const requestData = requestManager.getRequestFromId(transactionId);
370
376
  if (requestData) {
371
377
  data = requestData.body ? requestData.body.concat(chunk.toString()) : chunk.toString();
@@ -62,14 +62,14 @@ function paramHook(shim, mod, moduleName) {
62
62
  shim.wrap(mod && mod.prototype, 'params', function wrapMatch(shim, fn) {
63
63
  logger.debug(`Instrumenting ${moduleName}.prototype.params`);
64
64
  return function wrappedMatch() {
65
- const segment = shim.getActiveSegment();
66
- if (segment && segment.transaction) {
67
- let request = requestManager.getRequestFromId(segment.transaction.id);
65
+ const transaction = shim.tracer.getTransaction();
66
+ if (transaction) {
67
+ let request = requestManager.getRequestFromId(transaction.id);
68
68
  try {
69
69
  const uri = this.path;
70
70
  if (request) {
71
71
  request.uri = uri;
72
- requestManager.setRequest(segment.transaction.id, request);
72
+ requestManager.setRequest(transaction.id, request);
73
73
  }
74
74
 
75
75
  } catch (error) {
@@ -97,7 +97,7 @@ function paramHook(shim, mod, moduleName) {
97
97
  }
98
98
  });
99
99
  }
100
- requestManager.setRequest(segment.transaction.id, request);
100
+ requestManager.setRequest(transaction.id, request);
101
101
  } catch (error) {
102
102
 
103
103
  }
@@ -19,6 +19,10 @@ const logger = API.getLogger();
19
19
  * @param {*} moduleName
20
20
  */
21
21
  function initialize(shim, mod, moduleName){
22
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.ldap_injection){
23
+ logger.warn('ldap_injection detection is disabled');
24
+ return;
25
+ }
22
26
  logger.info('Instrumenting '+ moduleName )
23
27
 
24
28
  if(moduleName==='ldapjs' || moduleName==='ldapts'){
@@ -32,6 +32,10 @@ module.exports = initialize;
32
32
  * @param {Shim} shim
33
33
  */
34
34
  function initialize(shim, mongodb, moduleName) {
35
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.nosql_injection){
36
+ logger.warn('nosql_injection detection is disabled');
37
+ return;
38
+ }
35
39
  logger.info(`Instrumenting ${moduleName}`);
36
40
  if (!mongodb) {
37
41
  return;
@@ -29,6 +29,10 @@ module.exports = initialize;
29
29
  */
30
30
  function initialize(shim, mysql, moduleName) {
31
31
  modName = moduleName;
32
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.sql_injection){
33
+ logger.warn('sql_injection detection is disabled');
34
+ return;
35
+ }
32
36
  logger.info("Instrumenting", moduleName);
33
37
  if (shim._moduleRoot.includes("mysql2")) {
34
38
  promiseInitialize(shim, mysql, moduleName);
@@ -13,6 +13,10 @@ const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
13
13
  const logger = API.getLogger();
14
14
 
15
15
  function initialize(shim, childProcess, moduleName) {
16
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.command_injection){
17
+ logger.warn('command_injection detection is disabled');
18
+ return;
19
+ }
16
20
  logger.info('Instrumenting child_process');
17
21
  execFileHook(shim, childProcess, moduleName);
18
22
  spawnHook(shim, childProcess, moduleName);
@@ -15,6 +15,10 @@ const logger = API.getLogger();
15
15
  const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
16
16
 
17
17
  module.exports = function initialize(shim, pgsql, moduleName) {
18
+ if(API && API.getNRAgent() && API.getNRAgent().config.security.exclude_from_iast_scan.iast_detection_category.sql_injection){
19
+ logger.warn('sql_injection detection is disabled');
20
+ return;
21
+ }
18
22
  logger.info('Instrumenting '+ moduleName)
19
23
  // allows for native wrapping to not happen if not necessary
20
24
  // when env var is true