newrelic 10.6.0 → 10.6.1
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.
- package/NEWS.md +6 -0
- package/esm-loader.mjs +40 -25
- package/package.json +1 -1
package/NEWS.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
### v10.6.1 (2023-08-01)
|
|
2
|
+
|
|
3
|
+
#### Security Improvements
|
|
4
|
+
|
|
5
|
+
* updated ESM loader to track instrumentation by url in a map instead of in url to avoid remote code execution. ([#1741](https://github.com/newrelic/node-newrelic/pull/1741)) ([c8dc779](https://github.com/newrelic/node-newrelic/commit/c8dc779c7799b234290b6f7eb1d0a4e07d692ef9))
|
|
6
|
+
|
|
1
7
|
### v10.6.0 (2023-07-26)
|
|
2
8
|
|
|
3
9
|
#### Miscellaneous Chores
|
package/esm-loader.mjs
CHANGED
|
@@ -89,14 +89,10 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
89
89
|
})
|
|
90
90
|
|
|
91
91
|
// Keep track of what we've registered so we don't double register (see: https://github.com/newrelic/node-newrelic/issues/1646)
|
|
92
|
-
registeredSpecifiers.set(url, specifier)
|
|
92
|
+
registeredSpecifiers.set(url, { specifier })
|
|
93
93
|
} else if (format === 'module') {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// add a query param to the resolved url so the load hook below knows
|
|
97
|
-
// to rewrite and wrap the source code
|
|
98
|
-
modifiedUrl.searchParams.set('hasNrInstrumentation', 'true')
|
|
99
|
-
resolvedModule.url = modifiedUrl.href
|
|
94
|
+
addNrInstrumentation(resolvedModule)
|
|
95
|
+
registeredSpecifiers.set(url, { specifier, hasNrInstrumentation: true })
|
|
100
96
|
} else {
|
|
101
97
|
logger.debug(`${specifier} is not a CommonJS nor ESM package, skipping for now.`)
|
|
102
98
|
}
|
|
@@ -105,6 +101,38 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
105
101
|
return resolvedModule
|
|
106
102
|
}
|
|
107
103
|
|
|
104
|
+
/**
|
|
105
|
+
* This is purely done so that we can import the incoming specifier
|
|
106
|
+
* in the load hook. It used to be used to determine if instrumentation existed
|
|
107
|
+
* for specifier but we found a RCE with that solution.
|
|
108
|
+
*
|
|
109
|
+
* @param {object} resolvedModule the result of call resolve on a specifier
|
|
110
|
+
*/
|
|
111
|
+
function addNrInstrumentation(resolvedModule) {
|
|
112
|
+
const modifiedUrl = new URL(resolvedModule.url)
|
|
113
|
+
modifiedUrl.searchParams.set('hasNrInstrumentation', 'true')
|
|
114
|
+
resolvedModule.url = modifiedUrl.href
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Extracts the href without query params
|
|
119
|
+
*
|
|
120
|
+
* @param {string} url url of specifier
|
|
121
|
+
* @returns {string} new url without hasNrInstrumentation query param
|
|
122
|
+
*/
|
|
123
|
+
function removeNrInstrumentation(url) {
|
|
124
|
+
let parsedUrl
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
parsedUrl = new URL(url)
|
|
128
|
+
url = parsedUrl.href.split('?')[0]
|
|
129
|
+
} catch (err) {
|
|
130
|
+
logger.error('Unable to parse url: %s, msg: %s', url, err.message)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return url
|
|
134
|
+
}
|
|
135
|
+
|
|
108
136
|
/**
|
|
109
137
|
* Hook chain responsible for determining how a URL should be interpreted, retrieved, and parsed.
|
|
110
138
|
*
|
|
@@ -123,30 +151,17 @@ export async function load(url, context, nextLoad) {
|
|
|
123
151
|
return nextLoad(url, context, nextLoad)
|
|
124
152
|
}
|
|
125
153
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
parsedUrl = new URL(url)
|
|
130
|
-
} catch (err) {
|
|
131
|
-
logger.error('Unable to parse url: %s, msg: %s', url, err.message)
|
|
132
|
-
return nextLoad(url, context, nextLoad)
|
|
133
|
-
}
|
|
154
|
+
url = removeNrInstrumentation(url)
|
|
134
155
|
|
|
135
|
-
const
|
|
156
|
+
const pkg = registeredSpecifiers.get(url)
|
|
136
157
|
|
|
137
|
-
if (!hasNrInstrumentation) {
|
|
158
|
+
if (!pkg?.hasNrInstrumentation) {
|
|
138
159
|
return nextLoad(url, context, nextLoad)
|
|
139
160
|
}
|
|
140
161
|
|
|
141
|
-
|
|
142
|
-
* undo the work we did in the resolve hook above
|
|
143
|
-
* so we can properly rewrite source and not get in an infinite loop
|
|
144
|
-
*/
|
|
145
|
-
parsedUrl.searchParams.delete('hasNrInstrumentation')
|
|
162
|
+
const { specifier } = pkg
|
|
146
163
|
|
|
147
|
-
const
|
|
148
|
-
const specifier = registeredSpecifiers.get(originalUrl)
|
|
149
|
-
const rewrittenSource = await wrapEsmSource(originalUrl, specifier)
|
|
164
|
+
const rewrittenSource = await wrapEsmSource(url, specifier)
|
|
150
165
|
logger.debug(`Registered module instrumentation for ${specifier}.`)
|
|
151
166
|
|
|
152
167
|
return {
|