pnpm 11.7 Adds `frozenStore` for Read-Only Filesystems, Lets pacquet Resolve Dependencies, and Closes a Lockfile Path-Traversal

pnpm 11.7 Adds `frozenStore` for Read-Only Filesystems, Lets pacquet Resolve Dependencies, and Closes a Lockfile Path-Traversal

lschvn

pnpm 11.7.0 shipped on June 15, 2026, four days after the 11.6.0 security release that fixed the .npmrc environment-variable expansion vulnerability (GHSA-3qhv-2rgh-x77r). The 11.7 line picks up where 11.6 left off on the supply-chain hardening story and adds three features that change how teams run pnpm in containerized and reproducible-build environments: a --frozen-store install mode for read-only filesystems, full dependency-resolution delegation to the pacquet Rust port, and an opt-in batch mode for pnpm publish --recursive. There is also a real lockfile security fix that closes a path-traversal edge case the June 2026 npm supply chain attack retrospective flagged as a recurring class of bug across the ecosystem.

frozenStore: installs against a read-only package store

The headline feature of 11.7 is frozenStore (config key) and --frozen-store (CLI flag), an install mode for environments where the package store is on a read-only filesystem: a Nix store, an OCI image layer, a read-only bind mount, or a dm-verity rootfs. The store's SQLite index.db is opened with the immutable=1 URI, which bypasses the WAL/-shm sidecar creation that would otherwise fail with EROFS on a read-only directory. Every store-write path is suppressed: the index.db writer, the project-registry write, the side-effects cache, and the chmod that normally makes a bin executable when it crosses a read/write boundary.

The intended pairing is --offline --frozen-lockfile --frozen-store against a fully-populated store. Under the global virtual store (the default since 9.x), package directories live inside the store, so if the store is missing the build output of a package whose lifecycle scripts are approved (or that has a pnpm patch applied), pnpm fails up front with ERR_PNPM_FROZEN_STORE_NEEDS_BUILD rather than crashing mid-build on a read-only write. If the store is missing its content directory entirely, the install fails fast with ERR_PNPM_FROZEN_STORE_INCOMPLETE rather than attempting to initialize it.

There are two hard constraints to be aware of. The immutable=1 URI requires Node.js 22.15.0, 23.11.0, or 24.0.0 or later; on older runtimes, --frozen-store fails with a clear ERR_PNPM_FROZEN_STORE_UNSUPPORTED_NODE error. And --frozen-store is incompatible with --force and with a configured pnpr server, since both write into the store. Bin-linking also tolerates a read-only store: under the global virtual store, a package's bin source lives inside the store, so the chmod that makes it executable would be refused. With EPERM/EACCES or with EROFS on a genuinely read-only filesystem, pnpm now skips the chmod when the bin source is already executable and has a normalized shebang, and otherwise still errors out. The chmod is redundant when the seed already ships its bins executable.

The result is a fully reproducible install that can be cached as a single artifact and reused across CI, local dev, and production without any write access to the store. For Nix and OCI users, this is the missing piece: pnpm 11.6 was already usable in those environments, but every install would attempt a WAL chmod or a sidecar shm write that would either fail or fall back to a slower code path. 11.7 makes the read-only case the explicit, supported mode.

pacquet now resolves dependencies, not just materializes

The second feature is a milestone for the pacquet Rust port of pnpm: dependency resolution joins materialization in the set of operations pacquet can do end-to-end. The new behavior is opt-in via configDependencies: when pacquet is declared in configDependencies and the installed pacquet is at least 0.11.7, a default non-frozen install (isolated nodeLinker, plain pnpm install) is delegated to pacquet in a single pass. pacquet reads the manifests, writes pnpm-lock.yaml, and creates node_modules. pnpm detects the capability from the installed pacquet's version; older releases keep the resolve-then-materialize split.

pnpm add, pnpm update, and pnpm remove still resolve in pnpm itself, because those commands have to mutate the manifests before any resolution can happen. After the manifest is mutated, pacquet materializes. The lockfile format does not change. This remains an opt-in preview of the Rust install engine, tracked under #11723. For projects already running pacquet in frozen-install mode, the change is invisible: the resolution and materialization are already a single pacquet invocation. For projects still running on the Node.js install engine, the upgrade is a no-op as long as pacquet is not in configDependencies.

Lockfile path-traversal and reserved alias rejection

The third headline item is a security fix in the lockfile verifier. Before 11.7, an attacker who could control a lockfile entry (a malicious postinstall, a tampered CI artifact, a poisoned peer dependency's resolved spec) could set a dependency alias to a path-traversal string like ../../../escape or to a reserved name like .bin, .pnpm, or node_modules. Under nodeLinker: hoisted, the alias was joined directly under node_modules, letting package files be written outside the install root or overwrite pnpm-owned layout. The exploit class is the same one the esbuild 0.28.1 Windows path traversal (GHSA-g7r4-m6w7-qqqr) and the March 2026 Axios npm supply chain attack each surfaced in a different tool.

The 11.7 fix adds two layers. The hoisted graph builder now validates each alias at the directory sink (safeJoinModulesDir), matching the validation pnpm already performs for manifest-sourced aliases. And the lockfile verification gate (verifyLockfileResolutions) runs an always-on, policy-independent check that rejects any importer or snapshot dependency alias that is not a valid package name, failing the install early, before any fetch or filesystem work, for every node linker at once. The check is conservative: any alias that is not a syntactically valid package name (no /, no .., no reserved segments) is rejected with a clear error.

For a normal project, the practical effect is that an existing lockfile continues to install as before, and a lockfile with a path-traversal or reserved alias (which would be a previously-crafted attack, not a normal entry) now fails the install with a clear error. The fix does not change the lockfile format. It is the kind of defense-in-depth that the 11.6.0 .npmrc advisory also embodied: a project that already trusts its lockfile source still benefits from the verifier, because the verifier protects against bugs in the lockfile generator and against partial corruption.

--batch for pnpm publish --recursive

The fourth feature is a small but practical one: pnpm publish --recursive --batch sends all selected packages to the registry in a single PUT /-/pnpm/v1/publish request instead of one request per package. The target registry has to implement the batch publish endpoint (pnpr does); registries that don't are reported with a clear ERR_PNPM_BATCH_PUBLISH_UNSUPPORTED error. The batch is processed all-or-nothing by pnpr: if any package in the batch fails validation, none of the packages are published. For monorepos that publish N packages per release, the wall-clock win on pnpm publish --recursive is roughly Nx.

Other fixes that affect day-to-day work

The 11.7 release also fixes several correctness and regression bugs that have been open since 11.6. The most notable is a Windows regression in pnpm add that produced Cannot destructure property 'manifest' of 'manifestsByPath[rootDir]' as it is undefined when running outside a workspace; the root cause was selectProjectByDir keying the ProjectsGraph by opts.dir instead of project.rootDir, so downstream manifestsByPath lookups missed when the two paths normalized differently (typically drive-letter casing). The pnpm patch-remove command also no longer removes files outside the configured patches directory. pnpm publish now respects strictSsl: false for self-signed certificates the same way pnpm install does. Git dependencies that point to a subdirectory of a repository (repo#commit&path:/sub/dir) keep their path in the lockfile again after an integrity-pin regression in 11.6. And the shared package child resolution is now deterministic when the same package is reached through multiple contexts, fixing a class of "missing peer" reports (#12358) where request timing decided the child context.

The pnpm update -i and pnpm audit --fix -i interactive prompts also got a UX fix: the summary line after pressing Enter used to print every selected choice's full table row (label, current/target versions, workspace, URL) joined by commas, producing a wall of text. The summary now lists only the selected package names (or vulnerability keys). This is a small thing, but it is the kind of polish that separates a 11.7 minor release from a 11.6 patch.

Frequently Asked Questions

Related articles

More coverage with overlapping topics and tags.

Claude Code Issue #74066: Users Report Cross-Workspace Context Bleed on Sonnet 5, Anthropic Has Not Yet Responded
security

Claude Code Issue #74066: Users Report Cross-Workspace Context Bleed on Sonnet 5, Anthropic Has Not Yet Responded

An open bug filed against Claude Code on 2026-07-04 by an [Enterprise ZDR](https://docs.anthropic.com/en/docs/build-with-claude/zero-data-retention) user describes a working session on Sonnet 5 that suddenly starts referencing an unrelated Minecraft temple build, then doubles down on the wrong task in its recap. The reporter (GitHub: [@milesrichardson-edb](https://github.com/milesrichardson-edb), issue [anthropics/claude-code#74066](https://github.com/anthropics/claude-code/issues/74066)) is on Enterprise Zero Data Retention, the tier Anthropic specifically advertises as session-isolated. Triage on the reporter's local session JSONL at `~/.claude/projects/<encoded-cwd>/<session-id>.jsonl` finds the leaked text is not in the transcript, ruling out a local context bleed by file overlap. Four other users in the comments (with work histories going back to last year) describe near-identical behavior across Claude Code, Claude Mobile, and Claude deep research. The most plausible architectural fit is shared KV-cache state in inference ([per @yv3nne in the comments](https://github.com/anthropics/claude-code/issues/74066#issuecomment-4880448776)), but no Anthropic engineer has commented on the issue in the 22 hours since it was filed, and the issue reached the top of [Hacker News](https://news.ycombinator.com/item?id=42481789) on 2026-07-04. The tone in the thread is split: half suspecting a real platform cache reuse, half suspecting a [sonnet-5-specific hallucination triggered by a Pygments lexer](https://github.com/anthropics/claude-code/issues/74066#issuecomment-4880334711). Both readings are credible.
Oxlint v1.72 and Oxfmt v0.57 Land the v0.138 Crates Cycle, Unify the AstBuilder, and Retire the Prettier CSS/GraphQL Fallback
tooling

Oxlint v1.72 and Oxfmt v0.57 Land the v0.138 Crates Cycle, Unify the AstBuilder, and Retire the Prettier CSS/GraphQL Fallback

Oxlint apps_v1.72.0 and oxfmt apps_v0.57.0, both published on 2026-06-29, close out the v0.138 crates cycle predicted in the [v1.71 release notes](/articles/2026-06-23--oxlint-v1-71-oxfmt-v0-56). The crates release (crates_v0.138.0, also 2026-06-29) unifies the old and new AstBuilder APIs (#23876, #23834, #23831, with legacy methods marked `#[deprecated]`), renames `AllocatorAccessor` to `GetAllocator` and switches its `allocator` method to take `&self` (#23675, #23676), makes `Str` and `Ident` methods take `&GetAllocator` (#23781), adds `transformer_plugins: Support typeof define keys` for vue-i18n and similar macros (#23605, Alexander Lichter), and ships the headline perf entry of the cycle: `minifier: memoize value_type to remove its O(n^2) re-walk on long binary chains` (#23929, Dunqing), which turns a 20k-term arithmetic-addition chain from 6,118 ms to 4.7 ms (~1300x) and a real-world antd.js bundle from 78.1 ms to 65.4 ms. Oxlint v1.72.0 ships 3 features (React `no-unknown-property` suggestion #23936, AstBuilder unification #23875, `eslint/no-restricted-import` schema #23642), 18 bug fixes, and 23 performance entries. Oxfmt v0.57.0 carries two BREAKING changes that retire the Prettier fallback for CSS/LESS/SCSS and GraphQL files: `Format parser:css,less,scss files + css-in-js by oxc_formatter_css` (#23321, leaysgur) and `Support draft syntax with removing prettier fallback` (#23326, leaysgur), both landing on top of the new `oxc_formatter_css` (#23320) and `oxc_formatter_graphql` (#23317) crates.
Deno 2.9 Ships 1.98x Faster Cold Start, 2.2-3.1x Less RSS Under Load, Default-On npm Minimum Release Age, No-Downgrade Trust Policy, and Built-In Snapshot Testing
security

Deno 2.9 Ships 1.98x Faster Cold Start, 2.2-3.1x Less RSS Under Load, Default-On npm Minimum Release Age, No-Downgrade Trust Policy, and Built-In Snapshot Testing

Deno 2.9 (Bartek Iwańczuk, published 2026-06-25 on deno.com/blog/v2.9) is the largest Deno release of the cycle. Cold start drops from 34.2 ms to 17.3 ms (1.98x), peak RSS on the Deno.serve realworld workload drops 2.2x (142 MB → 64 MB) and 3.1x on 1 MiB bodies (197 MB → 63 MB), and Deno.serve throughput climbs 1.27x realworld (56.8k → 72.4k req/s), 1.11x plaintext, and 1.18x on 1 MiB bodies. Supply chain hardening: npm minimum-release-age is enabled by default with a 24h window (PR #35458), and a new opt-in no-downgrade trust policy (PR #34927) refuses to resolve any version whose trust evidence (staged publish, trusted publishing, provenance attestation) is weaker than the strongest evidence on any earlier-published version of the same package. Test runner parity: built-in t.assertSnapshot() (#35139), Deno.test.each (#34938), --shard for CI fan-out (#35057), retry and repeats (#35053), change-aware --changed and --related (#35199), and coverage thresholds (#35056). Lockfile interop: deno install seeds deno.lock from package-lock.json, pnpm-lock.yaml, yarn.lock, or bun.lock (#34296, #35330, #35346, #35350, #35394), pnpm-workspace.yaml auto-migrates to deno.json / package.json (#34993), and git merge conflict markers in deno.lock auto-resolve (#34726). Plus: deno desktop graduates from experimental (the June 16 PR #33441), deno link / deno unlink / deno list / deno watch subcommands, stable --unsafe-proto (#34738), Web Locks API (#31166), Happy Eyeballs v2 (RFC 8305) (#31726), navigator.userAgentData (#34743), the WebCrypto Modern Algorithms proposal (ML-KEM, ML-DSA, SLH-DSA, ChaCha20-Poly1305, SHA-3 family, KMAC, Argon2) (#34447, #34448, #34914, #35223), Node 26.3.0 compat (#34746, #34747), Node-API v10 (#35270), and CSS module imports under --unstable-raw-imports (#35093). 165+ PRs land in this cycle.

Comments

Log in Log in to join the conversation.

No comments yet. Be the first to share your thoughts.