Jan 27, 2026·5 min read·39 visits
pnpm versions prior to 10.28.1 contain a Windows-specific path traversal vulnerability. The extraction logic checked for Unix-style traversal attempts (`./`) but ignored Windows-style backslashes (`.\`). This allows malicious packages to write files outside their installation directory, potentially overwriting configuration files or injecting code into CI/CD pipelines.
A logic error in pnpm's tarball parsing mechanism allowed for arbitrary file writes on Windows systems. By using backslashes (`\`) instead of forward slashes (`/`) in path names, attackers could bypass sanitization checks designed to prevent directory traversal.
pnpm is the darling of the JavaScript ecosystem. It saves disk space, it's fast, and it uses a clever content-addressable store to manage dependencies. But in the race for performance, handling file system nuances often gets tricky—especially when you cross the bridge from the clean, predictable world of POSIX (Linux/macOS) to the wild west of Windows.
At the heart of any package manager is the ability to take a compressed archive (a tarball) and explode it onto the disk. This is a high-risk operation. You are essentially taking untrusted instructions on where to put bytes on a user's machine. If you aren't paranoid about the file paths inside that archive, you're going to have a bad time.
The vulnerability in question, CVE-2026-23889, hides in the parseTarball.ts file. This component is responsible for reading the entries of a package and deciding where they go. Ideally, it keeps them locked inside a designated folder. But on Windows, pnpm's bouncer was checking for the wrong kind of fake ID.
The root cause here is a classic "It Works On My Machine" error, assuming the developer's machine was a Mac or Linux box. To prevent path traversal (the act of escaping the extraction directory using ../), pnpm attempted to sanitize filenames.
The logic relied on a simple string check: fileName.includes('./'). If the path looked like it was trying to be clever with relative paths using forward slashes, pnpm would trigger a normalization routine to flatten it safely.
Here is the fatal flaw: Windows is bilingual. It speaks both Forward Slash (/) and Backslash (\).
If an attacker crafts a tarball entry named package\..\..\malicious.exe, the string does not contain ./. Therefore, pnpm's guard logic looks at it, shrugs, and says, "Looks safe to me!" It then passes this path to the Windows file system APIs. Windows, helpful as ever, interprets the backslashes as directory separators, processes the .., and walks up the directory tree, writing the file wherever the attacker pointed it.
Let's look at the smoking gun in store/cafs/src/parseTarball.ts. The vulnerable code was checking exclusively for the Unix convention.
Vulnerable Implementation:
// If it doesn't have './', it assumes it's safe.
if (fileName.includes('./')) {
fileName = path.posix.join('/', fileName).slice(1)
}The fix, applied in commit 6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0, is a lesson in defensiveness. It explicitly checks for the Windows backslash sequence and, crucially, normalizes all backslashes to forward slashes before doing any path math.
Patched Implementation:
// Check for both ./ AND .\
if (fileName.includes('./') || fileName.includes('.\\')) {
// 1. Replace all backslashes with forward slashes
// 2. Use POSIX join to resolve the '..' safely
fileName = path.posix.join('/', fileName.replaceAll('\\', '/')).slice(1)
}By converting \ to / first, path.posix.join can correctly interpret the traversal attempts and neutralize them, regardless of the operating system the code is running on.
Exploiting this requires creating a valid tarball that breaks the rules. Standard tools like npm pack or tar usually normalize paths for you, so a script kiddie might struggle to generate the payload. We need to go lower level or manually edit the archive headers.
The Attack Chain:
package/index.js to something spicy like package\..\..\..\Users\ContainerAdministrator\.npmrc.windows-fs-helper.pnpm install windows-fs-helper, pnpm extracts the file. Because of the missing check, the file system writes our payload to the user's home directory instead of the node_modules folder.You might ask, "So I can write a file. Big deal." In the context of a package manager, Arbitrary File Write is usually Game Over.
Supply Chain Poisoning: By overwriting .npmrc, an attacker can change the registry URL. The next time the developer (or the CI server) runs install, they are pulling packages from the attacker's server, not the official one. This grants persistent MITM capabilities.
CI/CD RCE: On build servers, overwriting a script that is about to be executed (like a post-build step or a GitHub Actions workflow file) leads directly to Remote Code Execution. Since the pnpm process already has write access to the disk, the barrier to entry is low.
This vulnerability is strictly Integrity based (CVSS 6.5), but in a development environment, integrity loss almost always leads to confidentiality loss (stealing env vars) or availability loss (breaking the build).
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
pnpm pnpm | < 10.28.1 | 10.28.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-22 |
| CVSS v3.1 | 6.5 (Medium) |
| Attack Vector | Network (Malicious Package) |
| Impact | Arbitrary File Write |
| Affected OS | Windows |
| Fix Commit | 6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0 |
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
An uncontrolled resource consumption vulnerability exists in the Scala-based http4s-blaze-server package of the http4s/blaze library. The vulnerability allows remote, unauthenticated attackers to cause an Out of Memory Error (OOM) and JVM crash by streaming a continuous sequence of small or empty WebSocket continuation frames with the FIN bit set to 0. This bypasses typical payload size checks because of the JVM's per-object allocation overhead, leading to rapid heap exhaustion with minimal network bandwidth.
A critical path traversal vulnerability has been identified in the OpenList Go-based backend package. The vulnerability exists within the batch rename handler because the application does not validate the source filename parameter before constructing filesystems paths. This omission allows authenticated users to escape their designated directory and rename files in sibling paths.
OpenList version 4.2.3 and prior is vulnerable to an authorization bypass and metadata leakage. When configured with the Bleve search engine backend, OpenList fails to perform separator-aware path matching when validating tenant containment. This allows authenticated users to access sibling directories sharing similar name prefixes. Furthermore, the search backend returns unfiltered global result counts, leaking existence verification data of unauthorized files via side-channel analysis.
An authorization bypass vulnerability in OpenList version 4.2.3 and below allows authenticated users to read arbitrary files outside of their designated base directories due to an insecure path prefix check using Go's standard strings.HasPrefix function.
A security policy bypass vulnerability exists in the AWS API MCP Server (awslabs-aws-api-mcp-server) from version 0.2.13 through 1.3.46. When the server fails to load the read-only operations index during startup (due to transient network failures, file permission issues, or other exceptions), it logs a warning but continues running in an insecure, degraded state. Under this condition, the security policy engine fails open, silently skipping all subsequent security checks and consent prompts for the lifetime of the process. This permits unauthorized mutating AWS CLI commands to execute via indirect prompt injection attacks.
An incomplete escaping vulnerability in the npm package 'shescape' allows unauthenticated users to trigger dynamic shell expansions, absolute path disclosure, and command block break-outs on Unix and Windows systems.