CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-23889

pnpm Path Traversal: When Windows Backslashes Break the Rules

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 27, 2026·5 min read·39 visits

Executive Summary (TL;DR)

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.

The Hook: Fast, Efficient, and Slightly Blind

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 Flaw: The POSIX-Centric Blind Spot

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.

The Code: A Tale of Two Slashes

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.

The Exploit: Crafting the Poisoned Package

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:

  1. Target Selection: Identify a Windows-heavy environment. CI/CD runners (GitHub Actions Windows runners) are prime targets because they often run with elevated privileges and contain sensitive secrets in the environment.
  2. Payload Creation: We create a tar archive where the file name field in the header is modified from package/index.js to something spicy like package\..\..\..\Users\ContainerAdministrator\.npmrc.
  3. Delivery: Publish this package to the npm registry (or a private registry). Give it a benign name like windows-fs-helper.
  4. Execution: When the victim runs 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.

The Impact: Why This Matters

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).

Official Patches

pnpmpnpm v10.28.1 Release Notes

Fix Analysis (1)

Technical Appendix

CVSS Score
6.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N

Affected Systems

pnpm (Windows)Windows CI/CD Runners using pnpm

Affected Versions Detail

Product
Affected Versions
Fixed Version
pnpm
pnpm
< 10.28.110.28.1
AttributeDetail
CWE IDCWE-22
CVSS v3.16.5 (Medium)
Attack VectorNetwork (Malicious Package)
ImpactArbitrary File Write
Affected OSWindows
Fix Commit6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059Command and Scripting Interpreter
Execution
CWE-22
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

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.

Known Exploits & Detection

Internal AnalysisVulnerability inferred from patch analysis demonstrating missing backslash check.

Vulnerability Timeline

Fix committed to main branch
2026-01-15
pnpm v10.28.1 released
2026-01-19
Public disclosure via GHSA and CVE
2026-01-26

References & Sources

  • [1]GHSA-6x96-7vc8-cm3p
  • [2]NVD - CVE-2026-23889

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•1 day ago•GHSA-7PPR-R889-MCF2
7.5

GHSA-7PPR-R889-MCF2: Unbounded WebSocket Message Aggregation in http4s-blaze-server leads to Denial of Service

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.

Alon Barad
Alon Barad
7 views•5 min read
•1 day ago•GHSA-95CV-R8X4-VH75
7.6

GHSA-95cv-r8x4-vh75: Path Traversal Vulnerability in OpenList Batch Rename Handler

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.

Amit Schendel
Amit Schendel
8 views•7 min read
•1 day ago•GHSA-P6PH-3JX2-3337
4.3

GHSA-P6PH-3JX2-3337: Horizontal Privilege Escalation and Metadata Information Disclosure via Bleve Search in OpenList

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.

Amit Schendel
Amit Schendel
8 views•5 min read
•1 day ago•GHSA-86CX-WWF4-PHQ4
6.5

GHSA-86cx-wwf4-phq4: Path Prefix Confusion Authorization Bypass in OpenList

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.

Amit Schendel
Amit Schendel
7 views•6 min read
•1 day ago•CVE-2026-16584
7.0

CVE-2026-16584: Security Policy Bypass in AWS API MCP Server via Startup Initialization Failure

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.

Amit Schendel
Amit Schendel
12 views•7 min read
•1 day ago•GHSA-6V4M-FW66-8R4X
6.5

GHSA-6V4M-FW66-8R4X: Path Disclosure and Shell Expansion Bypass in Shescape

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.

Alon Barad
Alon Barad
6 views•7 min read