// threat brief

pnpm dependency alias path traversal: an indirect dependency can swap project folders for symlinks at install time, even with --ignore-scripts

CVSS
8.8 HIGH
CISA KEV
Not listed
Weakness
CWE-23

PlainCVE Team · Published 2026-09-24 · AI-assisted · Press brief ↓

Human review 2026-09-24Command tests: none yetReproduced: not yetVerification record ↓

pnpm didn't block '..' in dependency aliases, so a malicious package deep in the tree can swap project paths for symlinks, even with --ignore-scripts.

Who is affectedDevelopers and CI systems running pnpm install with pnpm before 10.34.0, or 11.0.0 up to (not including) 11.4.0. The malicious package can be an indirect dependency you never chose.
What happensThe install step itself only changes files: paths such as git hooks, script folders, local GitHub Actions or dist/ can be replaced with attacker content. Later, running git commit, tests, builds, CI steps or publishing may run or package that content.
What to do nowUpgrade pnpm to 10.34.0 or later (10.x) or 11.4.0 or later (11.x). The project offers no workaround other than upgrading.
View evidence(2)
  • Vendor / maintainerpnpm's advisory: upgrade to a fixed versiongithub.com
  • Our assessmentChecking whether project paths became symlinks is our suggestion based on how the flaw works; the vendor provides no check
Affected versionsAll versions before 10.34.0; 11.0.0 up to but not including 11.4.0 (per the maintainer GHSA; the CVE structured data says <10.33.4, which contradicts its own description)
View evidence: sources disagree(4)
  • CVE recordDisputedThe CVE record's description: versions before 10.34.0 and 11.4.0 are affectedPrior to 10.34.0 and 11.4.0, pnpm allows a transitive dependency alias from registry package metadata to contain path traversal segments.cveawg.mitre.org
  • CVE recordDisputedThe same CVE record's structured field puts the 10.x bound at below 10.33.4, which disagrees with its description"version":"< 10.33.4"cveawg.mitre.org
  • Vulnerability databaseGitLab's advisory database: before 10.34.0, and from 11.0.0 before 11.4.0All versions before 10.34.0, all versions starting from 11.0.0 before 11.4.0advisories.gitlab.com
  • Vendor / maintainerpnpm's own advisory: reproduced on pnpm 11.2.1This was reproduced with `pnpm@11.2.1`.github.com
Fixed versions10.34.0 or later (10.x); 11.4.0 or later (11.x)
View evidence(3)
  • Vendor / maintainerpnpm 10.34.0 release notes: aliases with path-traversal segments are rejectedReject dependency aliases that contain path-traversal segmentsapi.github.com
  • Vendor / maintainerpnpm 11.4.0 release notes: the same fixReject dependency aliases that contain path-traversal segmentsapi.github.com
  • CVE recordCVE record: fixed in 10.34.0 and 11.4.0This vulnerability is fixed in 10.34.0 and 11.4.0.cveawg.mitre.org
CVSS vector
Show full vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Timeline
  • First public 2026-05-28
CISA KEVNot listed(Not being in KEV does not mean it has not been exploited)
View evidence(2)
  • Our assessmentOur 2026-09-24 snapshot of the CISA KEV catalog does not list this CVE; not being listed does not mean it has not been exploited
  • CERT / governmentCISA's assessment in the CVE record: a public proof of concept exists (poc); this does not mean it has been exploited in the wild"Exploitation":"poc"cveawg.mitre.org

Blue team playbook

Check, fix / mitigate, respond, harden. Matching the affected versions does not mean you were compromised, and a check that finds nothing does not prove you are safe; each item says what it can and cannot show. Tagged steps point to where the attack flow below can be stopped.

DETECTCheckAm I affected? Any signs of compromise?
  1. 01Check your pnpm version

    10.x needs 10.34.0 or later, 11.x needs 11.4.0 or later. Check both developer machines and CI, which may pin an older version.

    Read-only check
    pnpm --version
  2. 02Check whether project paths became symlinks (PlainCVE suggestion)

    The project published no detection guidance or indicators of compromise. Based on the paths the advisory lists, check whether any became symlinks pointing into node_modules. In a normal project these are usually ordinary folders.

    Read-only check
    find .git/hooks .husky .githooks scripts tools bin tests dist .github/actions -maxdepth 1 -type l 2>/dev/null
MITIGATEFix / mitigatePatch; block it if you cannot patch yet
  1. 01Upgrade to 10.34.0 or 11.4.0 or later

    The fix rejects aliases with path traversal both when reading package manifests and when creating symlinks. The project offers no workaround besides upgrading.

RESPONDRespondIf you find signs of compromise
  1. 01If you find a suspicious symlink, assume code may have run

    This is PlainCVE's inference, not official guidance: any hook or script that ran from a swapped path should be treated as untrusted code execution. Remove the symlink, reinstall with a patched pnpm, and find the package that introduced the alias.

  2. 02Review credentials and published releases (precaution)

    There is no official rotation guidance. If untrusted code is confirmed to have run, rotate the credentials that machine or CI job could reach, and review packages published during that window. This is a precaution.

HARDENHardenPrevent the next one
  1. 01Don't treat --ignore-scripts as a complete defence

    It only stops packages running scripts during install. It doesn't stop the package manager itself writing files where it shouldn't, or code that fires later.

  2. 02Pin and regularly update pnpm in CI

    The same releases also fixed several other pnpm security issues; keeping the package manager itself current matters as much as updating dependencies.

  3. 03Review new indirect dependencies in lockfile changes

    The malicious alias can come from a package you never chose directly; during code review, watch for unfamiliar packages or aliases appearing in the lockfile.

Full remediation steps and notes
  1. Upgrade pnpm itself first, then reinstall dependencies. Using whatever method you installed pnpm with, move to 10.34.0 or later (10.x) or 11.4.0 or later (11.x), then confirm with pnpm --version. If your CI configuration pins a pnpm version, update that too.
  2. Order matters. For projects where an old pnpm installed dependencies you’re unsure of, after upgrading first check whether the paths above have become symlinks. Only commit, build or publish once they’re clean, so you don’t trigger a swapped hook or script along the way.
  3. No official workaround. The advisory offers no mitigation other than upgrading.
  4. The same releases also fixed several separate pnpm security issues (rejecting patch files that point outside the package, rejecting non-SHA git commit fields, scoping registry credentials to their own registry, and failing hard on tarball integrity mismatches), which is another reason to upgrade.

Attack flow

Read left to right: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Click an icon for details.

pnpm dependency alias path traversal: an indirect dependency can swap project folders for symlinks at install time, even with --ignore-scripts: 1. The attacker publishes a malicious package with a path-traversal alias → 2. A developer or CI job runs pnpm install → 3. pnpm uses the alias as a path and replaces a project path with a symlink → 4. A later git commit, test, build or CI step uses the swapped path → 5. Tampered build output may get publishedCVE-2026-50016 · pnpm dependency alias path traversal: an indirect dependency can swap project folders forsymlinks at install time, even with --ignore-scriptsAttackerYour systemExternalThe attacker publishes a malicious package with a path-traversal alias — The package's registry metadata declares a dependency alias containing '..' (go up one folder). An ordinary-looking package then depends on it. 1The attackerpublishes amalicious packagewith …A developer or CI job runs pnpm install — The malicious package can be an indirect dependency. Adding --ignore-scripts changes nothing, because the next step needs no script at all. 2A developer or CIjob runs pnpminstallpnpm uses the alias as a path and replaces a project path with a symlink — Older versions never checked that the final path stayed inside node_modules, so paths such as .git/hooks, .husky, scripts/, .github/actions/ or dist/ can become symlinks to the attacker's package folder. This step changes files; it does not run code. 3pnpm uses thealias as a pathand replaces aproject path wit…A later git commit, test, build or CI step uses the swapped path — Only now might the attacker's content run, for example a git hook firing on commit, or pnpm test, pnpm run build or a CI step calling a swapped script. 4A later gitcommit, test,build or CI stepuses the swappe…Tampered build output may get published — The advisory lists dist/ and pnpm publish as possible trigger points; if output is swapped before publishing, downstream users could receive a tampered package. This is an inference from the advisory's impact list. 5Tampered buildoutput may getpublishedAttack pathCan be stopped herePlainCVE · plaincve.date/en/vulns/cve-2026-50016-pnpm-alias-path-traversal · CC BY 4.0
Free to use in reporting and teaching under CC BY 4.0. Attribution is already on the image.
  1. Attacker

    The attacker publishes a malicious package with a path-traversal alias

    The package's registry metadata declares a dependency alias containing '..' (go up one folder). An ordinary-looking package then depends on it.

    Defense: Fixed pnpm versions reject aliases containing path traversal as soon as they read the package manifest.

  2. Your system

    A developer or CI job runs pnpm install

    The malicious package can be an indirect dependency. Adding --ignore-scripts changes nothing, because the next step needs no script at all.

    Defense: Upgrade to 10.34.0 / 11.4.0 or later; review new indirect dependencies in lockfile changes.

  3. Your system

    pnpm uses the alias as a path and replaces a project path with a symlink

    Older versions never checked that the final path stayed inside node_modules, so paths such as .git/hooks, .husky, scripts/, .github/actions/ or dist/ can become symlinks to the attacker's package folder. This step changes files; it does not run code.

    Defense: The fix also rejects traversal again when creating symlinks. You can periodically check whether these paths have turned into symlinks into node_modules.

  4. Your system

    A later git commit, test, build or CI step uses the swapped path

    Only now might the attacker's content run, for example a git hook firing on commit, or pnpm test, pnpm run build or a CI step calling a swapped script.

    Defense: Don't rely on --ignore-scripts alone; build and run CI in clean, patched environments.

  5. External

    Tampered build output may get published

    The advisory lists dist/ and pnpm publish as possible trigger points; if output is swapped before publishing, downstream users could receive a tampered package. This is an inference from the advisory's impact list.

    Defense: Before publishing, confirm dist/ is not a symlink, and publish from patched CI.

Who is affected

BranchAffectedFixed
10.x and earlierbefore 10.34.010.34.0
11.x11.0.0 up to (not including) 11.4.011.4.0

The damage happens at install time when both of these hold:

ConditionNotes
You use an affected pnpm version from the table aboveDeveloper machines and CI (continuous integration, the systems that build and test code automatically) both count
pnpm install runs on a dependency tree containing a malicious package with a traversal aliasIt can be a transitive dependency, meaning a package that one of your dependencies depends on

At that point project paths have already been swapped for symlinks, so the project’s files can no longer be trusted. If the swapped target is an ordinary file, the maintainer advisory says the result is usually denial of service (that file stops working).

What happens later depends on whether something uses the swapped path. If git hooks, test or build scripts, CI steps or publishing later read or run those paths, the problem can escalate to running malicious code or to poisoned published artifacts (for example a swapped dist/ folder being packed and published).

Using --ignore-scripts makes no difference. The sources don’t say whether installing from an existing lockfile (the file recording the exact version of every dependency) with --frozen-lockfile also triggers it.

How it works

pnpm supports “aliases”, which let a project install a package under a different name. The problem: pnpm accepted the alias a package declared in its registry metadata even when it contained .. (go up one folder), then joined that alias onto node_modules to decide where to create a symlink (a filesystem shortcut) during install. It didn’t reject .., and it didn’t check that the final path was still inside node_modules.

The result: a malicious package deep in the dependency tree can make pnpm install replace a path in your project with a symlink to its own folder. The advisory lists possible targets including .git/hooks, .husky, .githooks, scripts/, tools/, bin/, tests/, .github/actions/<name>, dist/ before publishing, and node_modules/.bin. This kind of weakness is called relative path traversal (CWE-23).

Mind the timing: the install step only changes files. It does not mean code runs at install time. The attacker’s content can only run later, when a person or CI job uses the swapped path, for example git commit firing a git hook, pnpm test, pnpm run build, a CI step, or pnpm publish.

Why --ignore-scripts doesn’t help. According to pnpm’s docs, this option stops pnpm running scripts defined in the package.json of the project and its dependencies (such as postinstall). It controls whether packages get to run code. Here, pnpm itself creates the harmful symlink during its normal linking step, and no script is needed at all. --ignore-scripts is still worth using, but it doesn’t cover “the package manager writing files where it shouldn’t”, and it doesn’t cover code that fires later through git hooks, builds or CI.

The flawed approach (conceptual illustration, not pnpm’s source code):

Show code example(js)
// aliasName comes from the package's registry metadata and is untrusted
const target = path.join(nodeModulesDir, aliasName)
createSymlink(packageDir, target)   // never checks target is still inside node_modules

The fixed approach:

Show code example(js)
if (hasTraversalSegment(aliasName)) throw new Error('invalid alias')
const target = path.resolve(nodeModulesDir, aliasName)
if (!isInside(nodeModulesDir, target)) throw new Error('invalid alias')
createSymlink(packageDir, target)

According to the release notes, the fixed versions reject aliases with path traversal both when reading package manifests and when creating symlinks.

Timeline

DateEvent
Not publicReported by researcher aszx87410
2026-05-27pnpm 11.4.0 and 10.34.0 released
2026-05-28Maintainer advisory GHSA-hwx4-2j3j-g496 published
2026-06-03Advisory updated
2026-06-25CVE-2026-50016 published; added to NVD
2026-06-26GitHub global advisory database entry published and reviewed; CVE record updated
2026-06-29NVD last modified (Analyzed)

Further reading

  • Affected-version data disagrees: the CVE record’s structured data (CNA: GitHub) and NVD’s page summary say < 10.33.4, but the same CVE’s description text, NVD’s own CPE configuration and the maintainer advisory all say < 10.34.0. The 10.33.4 release notes list only a git tarball integrity fix, not this alias fix, which first appears in 10.34.0. This page follows the maintainer advisory and treats 10.33.4 as still vulnerable.
  • Scoring: the only score is GitHub’s (CNA) CVSS 3.1 8.8, which NVD lists as secondary; NVD has published no score of its own, and there is no CVSS 4.0 score. CISA’s SSVC assessment is “proof of concept available, not automatable, total technical impact”. A proof of concept is not the same as attacks in the wild.
  • Exploitation: no source reports exploitation in the wild. Our 2026-09-24 snapshot of the CISA KEV catalog does not list this CVE; not being listed does not mean it has not been exploited.
  • Fix commit: neither the advisory nor the release notes link a specific commit or PR.
  • Related but separate issue: pnpm 11.11–11.14 (blog dated 2026-07-18) added further hardening that stops a crafted pnpm-lock.yaml from writing outside the virtual store; that post does not mention this CVE.
  • Some GitHub release pages were rendered with the year 2024, but the GitHub API and pnpm’s blog both give 2026-05-27.
  • Related weakness type: CWE-23 (relative path traversal).

Verification Reviewed and checked against sources; not yet reproduced in our lab

Reviewed2026-09-24

Verification records describe the environment and the result only, never reproduction steps or code that could attack other people’s systems. See our policy.

Sources

  1. AdvisoryTransitive dependency alias path traversal allows project path override via symlink replacement (GHSA-hwx4-2j3j-g496) · pnpm (GitHub), 2026-05-28 · accessed 2026-09-24
  2. AdvisoryGHSA-hwx4-2j3j-g496 repository advisory (API) · GitHub / pnpm, 2026-05-28 · accessed 2026-09-24
  3. AdvisoryGHSA-hwx4-2j3j-g496 global advisory (API) · GitHub, 2026-06-26 · accessed 2026-09-24
  4. CVE / NVD / OSVCVE-2026-50016 · CVE Program, 2026-06-25 · accessed 2026-09-24
  5. CVE / NVD / OSVCVE-2026-50016 record JSON · CVE Program (CNA GitHub_M, CISA ADP), 2026-06-25 · accessed 2026-09-24
  6. CVE / NVD / OSVNVD - CVE-2026-50016 · NIST NVD, 2026-06-25 · accessed 2026-09-24
  7. CVE / NVD / OSVNVD CVE API record for CVE-2026-50016 · NIST NVD, 2026-06-25 · accessed 2026-09-24
  8. Patch / releaseRelease v10.34.0 · pnpm (GitHub), 2026-05-27 · accessed 2026-09-24
  9. Patch / releaseRelease v11.4.0 · pnpm (GitHub), 2026-05-27 · accessed 2026-09-24
  10. Patch / releaseRelease v10.33.4 · pnpm (GitHub) · accessed 2026-09-24
  11. Vendorpnpm 11.4 · pnpm, 2026-05-27 · accessed 2026-09-24
  12. Vendorpnpm 11.11-11.14 · pnpm, 2026-07-18 · accessed 2026-09-24
  13. Vendorpnpm install · pnpm · accessed 2026-09-24
  14. AdvisoryCVE-2026-50016: pnpm: Transitive dependency alias path traversal allows project path override via symlink replacement · GitLab Advisory Database · accessed 2026-09-24

Press brief

In one sentence

pnpm is a widely used JavaScript package manager. Its install step had a path traversal flaw: a malicious package deep in the dependency tree could replace project folders, such as git hooks or build output, with symlinks pointing to itself, and the --ignore-scripts option many people rely on against malicious packages did not stop it. Fixed versions 10.34.0 and 11.4.0 were released on May 27, 2026. No source reports exploitation in the wild.

Key facts

Severity
CVSS 3.1 8.8 (scored by GitHub as CNA; NVD has no score of its own) services.nvd.nist.gov
Fixed versions
10.34.0 and 11.4.0 (released 2026-05-27) github.com
Maintainer advisory
GHSA-hwx4-2j3j-g496, published 2026-05-28 api.github.com
CVE published
2026-06-25 cveawg.mitre.org
Weakness and reporter
CWE-23 relative path traversal; reported by aszx87410 github.com

Confirmed

  • Affected pnpm versions use an indirect dependency's alias as a path at install time and can replace a project path with a symlink to a malicious package.
  • The maintainer advisory, the CVE and NVD all state the path replacement still happens with --ignore-scripts.
  • Fixed versions 10.34.0 and 11.4.0 reject aliases containing path traversal.
  • CISA's SSVC assessment: proof of concept available, not automatable, total technical impact.

Unconfirmed / disputed

  • 10.x affected range: the CVE structured data says <10.33.4, but the maintainer advisory, the CVE description and NVD's CPE configuration all say <10.34.0; the 10.33.4 release notes contain no such fix, so this page uses <10.34.0.
  • No source reports exploitation in the wild. Our 2026-09-24 snapshot of the CISA KEV catalog does not list this CVE; not being listed does not mean it has not been exploited.
  • Sources don't say whether installing from an older lockfile (--frozen-lockfile) also triggers it.
  • No specific fix commit or PR has been publicly linked.

Quotable line

--ignore-scripts takes away a package's ability to run code, but this time the one writing the files was the package manager itself.

Images

Download the share image (PNG) · Attack flow diagram (downloadable)

Please credit "PlainCVE" and link to this page. Full citation format is under "How to cite" below. Found a factual error? Report it.

How to cite this page

This article is CC BY 4.0. Please keep the attribution and link when republishing.

PlainCVE Team (2026). "pnpm dependency alias path traversal: an indirect dependency can swap project folders for symlinks at install time, even with --ignore-scripts". PlainCVE. https://plaincve.date/en/vulns/cve-2026-50016-pnpm-alias-path-traversal (accessed YYYY-MM-DD)
BibTeX
@misc{cve202650016pnpmaliaspathtraversal2026,
  title  = {pnpm dependency alias path traversal: an indirect dependency can swap project folders for symlinks at install time, even with --ignore-scripts},
  author = {PlainCVE Team},
  year   = {2026},
  howpublished = {PlainCVE},
  url    = {https://plaincve.date/en/vulns/cve-2026-50016-pnpm-alias-path-traversal},
  note   = {Updated 2026-09-24}
}