Skip to content

Commit 9469012

Browse files
committed
arborist: sanitize packageName in path construction for linked strategy
Add sanitizeName() to strip path traversal sequences from package names before using them in filesystem path construction. Applied at all 9 locations where packageName is interpolated into path.join() calls.
1 parent 1206f8b commit 9469012

1 file changed

Lines changed: 12 additions & 8 deletions

File tree

workspaces/arborist/lib/arborist/isolated-reifier.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ const { depth } = require('treeverse')
55
const crypto = require('node:crypto')
66
const { IsolatedNode, IsolatedLink } = require('../isolated-classes.js')
77

8+
const sanitizeName = (name) => name
9+
? name.replace(/\.\.[/\\]/g, '_').replace(/\.\.$/, '_').replace(/^[/\\]/, '')
10+
: name
11+
812
// generate short hash key based on the dependency tree starting at this node
913
const getKey = (startNode) => {
1014
const deps = []
@@ -29,7 +33,7 @@ const getKey = (startNode) => {
2933
.replace(/\+/g, '-')
3034
.replace(/\//g, '_')
3135
.replace(/=+$/m, '')
32-
return `${startNode.packageName}@${startNode.version}-${hash}`
36+
return `${sanitizeName(startNode.packageName)}@${startNode.version}-${hash}`
3337
}
3438

3539
module.exports = cls => class IsolatedReifier extends cls {
@@ -41,7 +45,7 @@ module.exports = cls => class IsolatedReifier extends cls {
4145
const newChild = new IsolatedNode({
4246
isInStore,
4347
location,
44-
name: node.packageName || node.name,
48+
name: sanitizeName(node.packageName) || node.name,
4549
optional: node.optional,
4650
package: pkg,
4751
parent: root,
@@ -135,7 +139,7 @@ module.exports = cls => class IsolatedReifier extends cls {
135139
node.root.path,
136140
'node_modules',
137141
'.store',
138-
`${node.packageName}@${node.version}`
142+
`${sanitizeName(node.packageName)}@${node.version}`
139143
)
140144
mkdirSync(dir, { recursive: true })
141145
// TODO this approach feels wrong and shouldn't be necessary for shrinkwraps
@@ -177,7 +181,7 @@ module.exports = cls => class IsolatedReifier extends cls {
177181
result.id = this.counter++
178182
/* istanbul ignore next - packageName is always set for real packages */
179183
result.name = result.isWorkspace ? (node.packageName || node.name) : node.name
180-
result.packageName = node.packageName || node.name
184+
result.packageName = sanitizeName(node.packageName) || node.name
181185
result.package = { ...node.package }
182186
result.package.bundleDependencies = undefined
183187

@@ -313,7 +317,7 @@ module.exports = cls => class IsolatedReifier extends cls {
313317
return
314318
}
315319
processed.add(key)
316-
const location = join('node_modules', '.store', key, 'node_modules', c.packageName)
320+
const location = join('node_modules', '.store', key, 'node_modules', sanitizeName(c.packageName))
317321
this.#generateChild(c, location, c.package, true, root)
318322
})
319323

@@ -346,7 +350,7 @@ module.exports = cls => class IsolatedReifier extends cls {
346350

347351
let from, nmFolder
348352
if (externalEdge) {
349-
const fromLocation = join('node_modules', '.store', key, 'node_modules', node.packageName)
353+
const fromLocation = join('node_modules', '.store', key, 'node_modules', sanitizeName(node.packageName))
350354
from = root.children.get(fromLocation)
351355
nmFolder = join('node_modules', '.store', key, 'node_modules')
352356
} else {
@@ -380,7 +384,7 @@ module.exports = cls => class IsolatedReifier extends cls {
380384

381385
let target
382386
if (external) {
383-
const toLocation = join('node_modules', '.store', toKey, 'node_modules', dep.packageName)
387+
const toLocation = join('node_modules', '.store', toKey, 'node_modules', sanitizeName(dep.packageName))
384388
target = root.children.get(toLocation)
385389
} else {
386390
target = root.inventory.get(dep.localLocation)
@@ -414,7 +418,7 @@ module.exports = cls => class IsolatedReifier extends cls {
414418
package: pkg,
415419
path: join(dep.root.localPath, nmFolder, dep.name),
416420
realpath: target.path,
417-
resolved: external ? `file:.store/${toKey}/node_modules/${dep.packageName}` : dep.resolved,
421+
resolved: external ? `file:.store/${toKey}/node_modules/${sanitizeName(dep.packageName)}` : dep.resolved,
418422
root,
419423
target,
420424
})

0 commit comments

Comments
 (0)