pnpm pacquet: Trust-Lockfile Dependency Alias Path Traversal
A crafted dependency alias in a pnpm lockfile can trick pacquet into creating symlinks outside the project boundary when running with --trust-lockfile or a frozen lockfile.

The problem
pacquet (the Rust port of pnpm) accepted arbitrary strings as dependency alias keys from a lockfile without validation. Any string, including relative traversal segments like ../../, was passed directly into filesystem join operations.
With --trust-lockfile or --frozen-lockfile, an attacker who controls the committed pnpm-lock.yaml can exploit this to create symlinks at arbitrary paths outside the project or node_modules boundary. Install-time operations including direct/transitive dep links, bin destinations, hoist targets, and virtual-store slots were all affected.
Proof of concept
A working proof-of-concept for this issue in pnpm, with the exact payload below.
# Malicious pnpm-lock.yaml snippet
lockfileVersion: '9.0'
importers:
.:
dependencies:
../../escaped-link:
specifier: 'npm:lodash@4.17.21'
version: 'lodash@4.17.21'
packages:
lodash@4.17.21:
resolution:
integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZromxTTD1a8tanABx6A==
# Then run:
$ pacquet install --frozen-lockfile --trust-lockfile
# Result: symlink created at ../../escaped-link outside the project rootThe root cause is that dependency alias keys read from the lockfile were passed without validation to path join helpers in every filesystem materialization path (symlinks, bins, hoists, virtual-store slots). Because Node/Rust path joining normalizes segments like ../, a key of ../../escaped-link resolves to a directory two levels above the project root.
The patch introduced a shared safe_join_modules_dir helper in pacquet/crates/package-manager/src/safe_join_modules_dir.rs. It is called before any directory creation, symlink, bin, or hoist operation and rejects names containing traversal segments, absolute paths, platform-specific separators, or reserved names such as .bin, .pnpm, and node_modules.
Rejections surface as ERR_PNPM_INVALID_DEPENDENCY_NAME.
The warm-install bypass (frozen-lockfile fast path) was also closed: snapshot slots and package names are now checked before store initialization, not just during the slow path. CWE-22 (Path Traversal) and CWE-59 (Link Following) both apply.
The fix
Upgrade pnpm to 12.0.0-alpha.5 or later (the pacquet-backed alpha track). The fix is in commit 51300fd41c5e4c8f47635108e373cc3d1f324fa7 via pull request #12872. If you are on the stable pnpm track, the equivalent lockfile alias validation landed in pnpm 11.4 and was hardened further in 11.7.
Avoid committing lockfiles from untrusted sources, and never run pacquet install --trust-lockfile against a lockfile you did not author.
Related research
- high · 7.1pnpm Hoisted Lockfile Alias Path Traversal ()
- high · 8.2pnpm Path Traversal via configDependencies Lockfile Entry Allows Symlink Escape
- high · 7.4pnpm Environment Secret Exfiltration via Proxy Settings in pnpm-workspace.yaml
- high · 8.8CVE-2026-55698CVE-2026-55698: pnpm Env Lockfile Package-Manager Integrity Bypass