VYPR
Moderate severityOSV Advisory· Published Jan 26, 2026· Updated Jan 27, 2026

pnpm scoped bin name Path Traversal allows arbitrary file creation outside node_modules/.bin

CVE-2026-23890

Description

pnpm is a package manager. Prior to version 10.28.1, a path traversal vulnerability in pnpm's bin linking allows malicious npm packages to create executable shims or symlinks outside of node_modules/.bin. Bin names starting with @ bypass validation, and after scope normalization, path traversal sequences like ../../ remain intact. This issue affects all pnpm users who install npm packages and CI/CD pipelines using pnpm. It can lead to overwriting config files, scripts, or other sensitive files. Version 10.28.1 contains a patch.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
pnpmnpm
< 10.28.110.28.1

Affected products

1
  • Range: 0.19.0, @pnpm/headless@0.6.2, @pnpm/utils@0.6.1, …

Patches

1
8afbb1598445

fix: prevent path traversal by validating bin names

https://github.com/pnpm/pnpmZoltan KochanJan 15, 2026via ghsa
3 files changed · +40 19
  • .changeset/kind-boxes-shake.md+6 0 added
    @@ -0,0 +1,6 @@
    +---
    +"@pnpm/package-bins": patch
    +"pnpm": patch
    +---
    +
    +Fixed a path traversal vulnerability in pnpm's bin linking. Bin names starting with `@` bypassed validation, and after scope normalization, path traversal sequences like `../../` remained intact.
    \ No newline at end of file
    
  • pkg-manager/package-bins/src/index.ts+16 19 modified
    @@ -39,24 +39,21 @@ async function findFiles (dir: string): Promise<string[]> {
       }
     }
     
    -function commandsFromBin (bin: PackageBin, pkgName: string, pkgPath: string) {
    -  if (typeof bin === 'string') {
    -    return [
    -      {
    -        name: normalizeBinName(pkgName),
    -        path: path.join(pkgPath, bin),
    -      },
    -    ]
    +function commandsFromBin (bin: PackageBin, pkgName: string, pkgPath: string): Command[] {
    +  const cmds: Command[] = []
    +  for (const [commandName, binRelativePath] of typeof bin === 'string' ? [[pkgName, bin]] : Object.entries(bin)) {
    +    const binName = commandName[0] === '@'
    +      ? commandName.slice(commandName.indexOf('/') + 1)
    +      : commandName
    +    // Validate: must be safe (no path traversal) - only allow URL-safe chars or $
    +    if (binName !== encodeURIComponent(binName) && binName !== '$') {
    +      continue
    +    }
    +    const binPath = path.join(pkgPath, binRelativePath)
    +    if (!isSubdir(pkgPath, binPath)) {
    +      continue
    +    }
    +    cmds.push({ name: binName, path: binPath })
       }
    -  return Object.keys(bin)
    -    .filter((commandName) => encodeURIComponent(commandName) === commandName || commandName === '$' || commandName[0] === '@')
    -    .map((commandName) => ({
    -      name: normalizeBinName(commandName),
    -      path: path.join(pkgPath, bin[commandName]),
    -    }))
    -    .filter((cmd) => isSubdir(pkgPath, cmd.path))
    -}
    -
    -function normalizeBinName (name: string): string {
    -  return name[0] === '@' ? name.slice(name.indexOf('/') + 1) : name
    +  return cmds
     }
    
  • pkg-manager/package-bins/test/index.ts+18 0 modified
    @@ -126,3 +126,21 @@ test('get bin from scoped bin name', async () => {
         ]
       )
     })
    +
    +test('skip scoped bin names with path traversal', async () => {
    +  expect(
    +    await getBinsFromPackageManifest({
    +      name: 'malicious',
    +      version: '1.0.0',
    +      bin: {
    +        '@scope/../../.npmrc': './malicious.js',
    +        '@scope/../etc/passwd': './evil.js',
    +        '@scope/legit': './good.js',
    +      },
    +    }, process.cwd())).toStrictEqual([
    +    {
    +      name: 'legit',
    +      path: path.resolve('good.js'),
    +    },
    +  ])
    +})
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.