From 8fab0fab35e90deb1cb90152f8db7600c2afd713 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 19 Feb 2026 18:54:13 +0800 Subject: [PATCH 1/5] fix: dont follow absolute paths outside job base --- src/analyze.ts | 43 +++++++++++++++++++ src/utils/ast-helpers.ts | 2 +- test/unit/pkg-dir-outside-base/input.js | 1 + test/unit/pkg-dir-outside-base/output.js | 6 +++ .../secret-dir/secret.txt | 1 + test/unit/pkg-file-outside-base/input.js | 1 + test/unit/pkg-file-outside-base/output.js | 6 +++ test/unit/pkg-file-outside-base/secret.txt | 1 + 8 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/unit/pkg-dir-outside-base/input.js create mode 100644 test/unit/pkg-dir-outside-base/output.js create mode 100644 test/unit/pkg-dir-outside-base/secret-dir/secret.txt create mode 100644 test/unit/pkg-file-outside-base/input.js create mode 100644 test/unit/pkg-file-outside-base/output.js create mode 100644 test/unit/pkg-file-outside-base/secret.txt diff --git a/src/analyze.ts b/src/analyze.ts index edf2b536..242a8b5f 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1170,8 +1170,51 @@ export default async function analyze( } if (wildcardIndex !== -1 && stats.isFile()) return; if (stats.isFile()) { + // do not emit file assets outside job.base + if (job.ignoreFn(path.relative(job.base, assetPath))) return; + // do not emit file assets outside the package boundary if inside node_modules + if (pkgBase) { + const nodeModulesBase = + id.substring(0, id.indexOf(path.sep + 'node_modules')) + + path.sep + + 'node_modules' + + path.sep; + if (!assetPath.startsWith(nodeModulesBase)) { + if (job.log) + console.log( + 'Skipping asset emission of ' + + assetPath + + ' for ' + + id + + ' as it is outside the package base ' + + pkgBase, + ); + return; + } + } assets.add(assetPath); } else if (stats.isDirectory()) { + // do not emit directory assets outside job.base + if (job.ignoreFn(path.relative(job.base, assetPath))) return; + if (pkgBase) { + const nodeModulesBase = + id.substring(0, id.indexOf(path.sep + 'node_modules')) + + path.sep + + 'node_modules' + + path.sep; + if (!assetPath.startsWith(nodeModulesBase)) { + if (job.log) + console.log( + 'Skipping asset emission of ' + + assetPath + + ' for ' + + id + + ' as it is outside the package base ' + + pkgBase, + ); + return; + } + } if (validWildcard(assetPath)) emitAssetDirectory(assetPath); } } diff --git a/src/utils/ast-helpers.ts b/src/utils/ast-helpers.ts index 895e8224..f28417a2 100644 --- a/src/utils/ast-helpers.ts +++ b/src/utils/ast-helpers.ts @@ -22,7 +22,7 @@ export function isIdentifierRead(node: Node, parent: Node) { return parent.id !== node; // disregard the `bar` in `export { foo as bar }` case 'ExportSpecifier': - return false; + return node.name === parent.exported.name; // disregard the `bar` in `function (bar) {}` case 'FunctionExpression': case 'FunctionDeclaration': diff --git a/test/unit/pkg-dir-outside-base/input.js b/test/unit/pkg-dir-outside-base/input.js new file mode 100644 index 00000000..878bb5e0 --- /dev/null +++ b/test/unit/pkg-dir-outside-base/input.js @@ -0,0 +1 @@ +require('some-pkg'); diff --git a/test/unit/pkg-dir-outside-base/output.js b/test/unit/pkg-dir-outside-base/output.js new file mode 100644 index 00000000..460f1dbe --- /dev/null +++ b/test/unit/pkg-dir-outside-base/output.js @@ -0,0 +1,6 @@ +[ + "package.json", + "test/unit/pkg-dir-outside-base/input.js", + "test/unit/pkg-dir-outside-base/node_modules/some-pkg/index.js", + "test/unit/pkg-dir-outside-base/node_modules/some-pkg/package.json" +] diff --git a/test/unit/pkg-dir-outside-base/secret-dir/secret.txt b/test/unit/pkg-dir-outside-base/secret-dir/secret.txt new file mode 100644 index 00000000..d97c5ead --- /dev/null +++ b/test/unit/pkg-dir-outside-base/secret-dir/secret.txt @@ -0,0 +1 @@ +secret diff --git a/test/unit/pkg-file-outside-base/input.js b/test/unit/pkg-file-outside-base/input.js new file mode 100644 index 00000000..878bb5e0 --- /dev/null +++ b/test/unit/pkg-file-outside-base/input.js @@ -0,0 +1 @@ +require('some-pkg'); diff --git a/test/unit/pkg-file-outside-base/output.js b/test/unit/pkg-file-outside-base/output.js new file mode 100644 index 00000000..f89e6308 --- /dev/null +++ b/test/unit/pkg-file-outside-base/output.js @@ -0,0 +1,6 @@ +[ + "package.json", + "test/unit/pkg-file-outside-base/input.js", + "test/unit/pkg-file-outside-base/node_modules/some-pkg/index.js", + "test/unit/pkg-file-outside-base/node_modules/some-pkg/package.json" +] diff --git a/test/unit/pkg-file-outside-base/secret.txt b/test/unit/pkg-file-outside-base/secret.txt new file mode 100644 index 00000000..4e7e76d9 --- /dev/null +++ b/test/unit/pkg-file-outside-base/secret.txt @@ -0,0 +1 @@ +secret content From 8751aae9c38f1a8566005e175179a75edc3cc50b Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 19 Feb 2026 19:07:26 +0800 Subject: [PATCH 2/5] we need the test node_modules --- test/unit/pkg-dir-outside-base/.gitignore | 1 + .../unit/pkg-dir-outside-base/node_modules/some-pkg/index.js | 3 +++ .../pkg-dir-outside-base/node_modules/some-pkg/package.json | 5 +++++ test/unit/pkg-file-outside-base/.gitignore | 1 + .../pkg-file-outside-base/node_modules/some-pkg/index.js | 3 +++ .../pkg-file-outside-base/node_modules/some-pkg/package.json | 5 +++++ 6 files changed, 18 insertions(+) create mode 100644 test/unit/pkg-dir-outside-base/.gitignore create mode 100644 test/unit/pkg-dir-outside-base/node_modules/some-pkg/index.js create mode 100644 test/unit/pkg-dir-outside-base/node_modules/some-pkg/package.json create mode 100644 test/unit/pkg-file-outside-base/.gitignore create mode 100644 test/unit/pkg-file-outside-base/node_modules/some-pkg/index.js create mode 100644 test/unit/pkg-file-outside-base/node_modules/some-pkg/package.json diff --git a/test/unit/pkg-dir-outside-base/.gitignore b/test/unit/pkg-dir-outside-base/.gitignore new file mode 100644 index 00000000..34a75639 --- /dev/null +++ b/test/unit/pkg-dir-outside-base/.gitignore @@ -0,0 +1 @@ +!node_modules diff --git a/test/unit/pkg-dir-outside-base/node_modules/some-pkg/index.js b/test/unit/pkg-dir-outside-base/node_modules/some-pkg/index.js new file mode 100644 index 00000000..a1fea6bb --- /dev/null +++ b/test/unit/pkg-dir-outside-base/node_modules/some-pkg/index.js @@ -0,0 +1,3 @@ +const s = '/../../secret-dir'; + +export { s }; diff --git a/test/unit/pkg-dir-outside-base/node_modules/some-pkg/package.json b/test/unit/pkg-dir-outside-base/node_modules/some-pkg/package.json new file mode 100644 index 00000000..d234a264 --- /dev/null +++ b/test/unit/pkg-dir-outside-base/node_modules/some-pkg/package.json @@ -0,0 +1,5 @@ +{ + "name": "some-pkg", + "version": "1.0.0", + "main": "index.js" +} diff --git a/test/unit/pkg-file-outside-base/.gitignore b/test/unit/pkg-file-outside-base/.gitignore new file mode 100644 index 00000000..34a75639 --- /dev/null +++ b/test/unit/pkg-file-outside-base/.gitignore @@ -0,0 +1 @@ +!node_modules diff --git a/test/unit/pkg-file-outside-base/node_modules/some-pkg/index.js b/test/unit/pkg-file-outside-base/node_modules/some-pkg/index.js new file mode 100644 index 00000000..2cb4abc8 --- /dev/null +++ b/test/unit/pkg-file-outside-base/node_modules/some-pkg/index.js @@ -0,0 +1,3 @@ +const s = '/../../secret.txt'; + +export { s }; diff --git a/test/unit/pkg-file-outside-base/node_modules/some-pkg/package.json b/test/unit/pkg-file-outside-base/node_modules/some-pkg/package.json new file mode 100644 index 00000000..d234a264 --- /dev/null +++ b/test/unit/pkg-file-outside-base/node_modules/some-pkg/package.json @@ -0,0 +1,5 @@ +{ + "name": "some-pkg", + "version": "1.0.0", + "main": "index.js" +} From 7e9644cf2ec2c0db063fa3e51df03d8e97301006 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 19 Feb 2026 19:23:32 +0800 Subject: [PATCH 3/5] deduplicate --- src/analyze.ts | 61 +++++++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 242a8b5f..64220c57 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1169,52 +1169,33 @@ export default async function analyze( return; } if (wildcardIndex !== -1 && stats.isFile()) return; + // do not emit assets outside the package boundary if inside node_modules + if (pkgBase) { + const nodeModulesBase = + id.substring(0, id.lastIndexOf(path.sep + 'node_modules')) + + path.sep + + 'node_modules' + + path.sep; + if (!assetPath.startsWith(nodeModulesBase)) { + if (job.log) + console.log( + 'Skipping asset emission of ' + + assetPath + + ' for ' + + id + + ' as it is outside the package base ' + + pkgBase, + ); + return; + } + } if (stats.isFile()) { // do not emit file assets outside job.base if (job.ignoreFn(path.relative(job.base, assetPath))) return; - // do not emit file assets outside the package boundary if inside node_modules - if (pkgBase) { - const nodeModulesBase = - id.substring(0, id.indexOf(path.sep + 'node_modules')) + - path.sep + - 'node_modules' + - path.sep; - if (!assetPath.startsWith(nodeModulesBase)) { - if (job.log) - console.log( - 'Skipping asset emission of ' + - assetPath + - ' for ' + - id + - ' as it is outside the package base ' + - pkgBase, - ); - return; - } - } assets.add(assetPath); } else if (stats.isDirectory()) { // do not emit directory assets outside job.base if (job.ignoreFn(path.relative(job.base, assetPath))) return; - if (pkgBase) { - const nodeModulesBase = - id.substring(0, id.indexOf(path.sep + 'node_modules')) + - path.sep + - 'node_modules' + - path.sep; - if (!assetPath.startsWith(nodeModulesBase)) { - if (job.log) - console.log( - 'Skipping asset emission of ' + - assetPath + - ' for ' + - id + - ' as it is outside the package base ' + - pkgBase, - ); - return; - } - } if (validWildcard(assetPath)) emitAssetDirectory(assetPath); } } @@ -1242,7 +1223,7 @@ export default async function analyze( // do not emit asset directories higher than the node_modules base if a package if (pkgBase) { const nodeModulesBase = - id.substring(0, id.indexOf(path.sep + 'node_modules')) + + id.substring(0, id.lastIndexOf(path.sep + 'node_modules')) + path.sep + 'node_modules' + path.sep; From 01f31c8a3534dcc5d288b0dae5780dc9e3bcee93 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 19 Feb 2026 19:24:19 +0800 Subject: [PATCH 4/5] revert --- src/analyze.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyze.ts b/src/analyze.ts index 64220c57..067b711a 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1172,7 +1172,7 @@ export default async function analyze( // do not emit assets outside the package boundary if inside node_modules if (pkgBase) { const nodeModulesBase = - id.substring(0, id.lastIndexOf(path.sep + 'node_modules')) + + id.substring(0, id.indexOf(path.sep + 'node_modules')) + path.sep + 'node_modules' + path.sep; From 3cab014fa49cf7d40700459eb200d854523ddc86 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 19 Feb 2026 19:24:53 +0800 Subject: [PATCH 5/5] revert --- src/analyze.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyze.ts b/src/analyze.ts index 067b711a..1b63ebd6 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1223,7 +1223,7 @@ export default async function analyze( // do not emit asset directories higher than the node_modules base if a package if (pkgBase) { const nodeModulesBase = - id.substring(0, id.lastIndexOf(path.sep + 'node_modules')) + + id.substring(0, id.indexOf(path.sep + 'node_modules')) + path.sep + 'node_modules' + path.sep;