From 3968292926789f88ca85e41f4a77fe36a4294287 Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Fri, 24 May 2024 17:28:02 +0300 Subject: [PATCH] fix: prevent `directory.man` referencing outside the package root (#104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What / Why The current `directories.man` handler allows to reach assets outside the package scope. ```js // expand directories.man if (steps.includes('mans') && !data.man && data.directories?.man) { const manDir = data.directories.man const cwd = path.resolve(pkg.path, manDir) const files = await lazyLoadGlob()('**/*.[0-9]', { cwd }) data.man = files.map(man => path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/') ) ``` ```js path.resolve(process.cwd(), '/') → '/' system root ``` ## References * continues https://github.com/npm/read-package-json/pull/177 * relates https://github.com/npm/package-json/pull/100 --- lib/normalize.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index e400dfd..0337a05 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -103,6 +103,10 @@ function isValidScopedPackageName (spec) { rest[1] === encodeURIComponent(rest[1]) } +function securePath (ref) { + return path.join('.', path.join('/', ref)) +} + // We don't want the `changes` array in here by default because this is a hot // path for parsing packuments during install. So the calling method passes it // in if it wants to track changes. @@ -327,7 +331,7 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase }) // expand directories.man if (steps.includes('mans') && !data.man && data.directories?.man) { const manDir = data.directories.man - const cwd = path.resolve(pkg.path, manDir) + const cwd = path.resolve(pkg.path, securePath(manDir)) const files = await lazyLoadGlob()('**/*.[0-9]', { cwd }) data.man = files.map(man => path.relative(pkg.path, path.join(cwd, man)).split(path.sep).join('/') @@ -340,7 +344,7 @@ const normalize = async (pkg, { strict, steps, root, changes, allowLegacyCase }) // expand "directories.bin" if (steps.includes('binDir') && data.directories?.bin && !data.bin) { - const binsDir = path.resolve(pkg.path, path.join('.', path.join('/', data.directories.bin))) + const binsDir = path.resolve(pkg.path, securePath(data.directories.bin)) const bins = await lazyLoadGlob()('**', { cwd: binsDir }) data.bin = bins.reduce((acc, binFile) => { if (binFile && !binFile.startsWith('.')) {