Safeguard
Vulnerability Analysis

path-parse regular expression denial of service (CVE-2021-23343)

A ReDoS flaw in path-parse (CVE-2021-23343) lurks deep in webpack and resolve dependency trees. Here's the impact, timeline, and how to fix it.

Nayan Dey
Security Researcher
7 min read

path-parse, a tiny utility that splits filesystem paths into their component parts (root, directory, base, name, extension), sits quietly in the dependency tree of thousands of JavaScript projects — pulled in transitively through webpack, resolve, browserify, and countless build toolchains. In late 2021, researchers disclosed CVE-2021-23343, a Regular Expression Denial of Service (ReDoS) flaw in path-parse versions prior to 1.0.7. The vulnerable regular expressions used internally to tokenize path strings exhibit catastrophic backtracking when fed specially crafted input, allowing an attacker who controls or influences a path string to force the Node.js event loop into pathological CPU consumption — freezing a single-threaded server process and denying service to every other request it would otherwise handle.

The severity of this bug isn't in its exploit sophistication — it's in its reach. path-parse is one of those "invisible" packages that almost nobody installs directly but almost everyone ships, which is exactly the profile of vulnerability that slips past manual dependency review and lingers in production for years.

What Is path-parse and Why It's Everywhere

path-parse exports a single function that mimics Node's built-in path.parse(), breaking a path string like /home/user/dir/file.txt into { root, dir, base, ext, name }. It became popular as a standalone, browser-compatible alternative to Node's native path module for tools that need to run path logic outside of Node (bundlers, resolvers, and polyfill shims in particular).

Its biggest distribution channel is the resolve package, which webpack, Babel, ESLint, and Browserify all depend on to implement Node-style module resolution. Because resolve is itself a near-ubiquitous transitive dependency, path-parse ends up nested three, four, even five levels deep in node_modules trees where developers never see it and SCA tools relying on top-level manifests often miss it.

The Vulnerability: Catastrophic Backtracking

path-parse's parse() function relies on a set of regular expressions to split the input string into path segments. Prior to version 1.0.7, these expressions used ambiguous, nested quantifiers (patterns combining greedy .* / .+ groups with adjacent optional groups) that can require exponential time to fail to match on certain crafted strings. When path-parse is handed a string engineered with a long run of repeating characters designed to trigger this backtracking — for example, a name padded with hundreds of separator-adjacent characters — the regex engine can enter a combinatorial exploration of match possibilities that takes seconds, then minutes, to resolve.

Because JavaScript's regex engine runs synchronously on the main thread, this isn't a memory-exhaustion bug or a crash — it's worse in some deployment contexts: the process keeps running but stops servicing anything else. In a Node.js API server that parses user-supplied file paths (upload handlers, static asset routers, template loaders, build tooling accepting user-controlled config paths), a handful of malicious requests can pin a CPU core at 100% and starve the event loop, producing an effective denial of service with almost no attacker infrastructure required.

Affected Versions and Components

  • Package: path-parse (npm)
  • Affected versions: All versions prior to 1.0.7
  • Fixed version: 1.0.7 and later
  • Advisory: GHSA-hj48-42vr-x3v9
  • Primary transitive vector: the resolve npm package (versions depending on vulnerable path-parse ranges), which is itself consumed by webpack, Babel, ESLint, Browserify, and a long tail of build and bundling tools

Because path-parse is almost never a direct dependency, the practical exposure surface is defined less by "do you use path-parse" and more by "do you use anything in the modern JavaScript build ecosystem" — which, for most organizations, is effectively yes. The exploitability in any given application still depends on whether attacker-controlled input reaches a path-parsing call at runtime (as opposed to only during a local build step), which is the key triage question defenders actually need answered.

CVSS, EPSS, and KEV Context

CVE-2021-23343 carries a CVSS v3.1 base score in the medium range (approximately 5.3), reflecting a network-exploitable, low-complexity denial-of-service condition with no privileges or user interaction required, and impact confined to availability rather than confidentiality or integrity. That "medium" label is doing a lot of quiet work here: CVSS scores ReDoS bugs conservatively because the base metric doesn't capture how much of your infrastructure sits behind a single vulnerable code path, or how a build-time-only dependency changes the practical blast radius.

Exploit Prediction Scoring System (EPSS) data for this CVE places it in a low observed-exploitation-probability band, consistent with most ReDoS findings in build-tooling dependencies — there is no widely circulated public exploit chain targeting it specifically, and it has not been added to CISA's Known Exploited Vulnerabilities (KEV) catalog. In practice, this means path-parse ReDoS is not a "drop everything" incident-response trigger, but it is squarely the kind of finding that accumulates unpatched across thousands of repositories precisely because nothing forces urgency — which is its own risk category.

Timeline

  • Vulnerability identified: The vulnerable regex patterns in path-parse's tokenizing logic were identified during security research into ReDoS patterns across widely-used npm utility packages.
  • Disclosure: The finding was reported to the path-parse maintainers through coordinated disclosure channels in 2021.
  • Fix released: path-parse 1.0.7 was published, replacing the vulnerable regular expressions with safer, linear-time equivalents.
  • CVE assignment: CVE-2021-23343 was assigned and published, alongside the corresponding GitHub Security Advisory (GHSA-hj48-42vr-x3v9).
  • Downstream propagation: Because path-parse is consumed almost entirely as a transitive dependency, the practical remediation timeline for most organizations extended well past the initial fix — bounded not by when the patch existed, but by when resolve, webpack, and other intermediate packages bumped their own dependency ranges and downstream projects regenerated lockfiles.

That gap between "patch available" and "patch actually installed across the dependency graph" is the recurring theme in transitive-dependency vulnerabilities, and it's precisely where most organizations' exposure window actually lives.

Remediation Steps

  1. Identify exposure across the full dependency graph, not just direct dependencies. Run npm ls path-parse or yarn why path-parse to enumerate every version and path by which it enters your tree — remember it is almost certainly nested under resolve, webpack, or similar tooling.
  2. Upgrade to path-parse 1.0.7 or later. If it appears as a direct dependency, bump it directly. If it's transitive, upgrade the intermediate package (commonly resolve) to a version that pins path-parse >=1.0.7.
  3. Force resolution where upgrading the parent isn't immediately possible. Use npm's overrides field, Yarn's resolutions field, or pnpm's overrides to pin path-parse to a safe version across the entire tree without waiting on every intermediate maintainer to release a bump.
  4. Regenerate and commit your lockfile after applying the override or upgrade, and verify with npm ls path-parse that no vulnerable version remains anywhere in the resolved tree.
  5. Assess runtime reachability before treating this as urgent. If path-parse only executes during your build step (webpack/Babel compilation in CI) and never touches attacker-controlled input at runtime, your actual exposure is materially lower than the CVSS score alone suggests — prioritize accordingly, but don't ignore it, since build pipelines that ingest user-influenced paths (monorepo tooling, plugin systems, CI triggered by external PRs) can still be exposed.
  6. Add a regression check (a dependency-audit step in CI, such as npm audit --audit-level=moderate or an SCA gate) so a future downgrade or transitive re-introduction doesn't silently reopen the issue.

How Safeguard Helps

This CVE is a textbook case for why dependency counting isn't security — path-parse sits four hops deep in most trees, and a scanner that only flags "vulnerable package present" will bury security teams in noise across thousands of repos that never actually execute the vulnerable code path with attacker-controlled input. Safeguard's reachability analysis traces whether your application's runtime call graph actually invokes the vulnerable path-parse regex logic on externally influenced data, separating genuine denial-of-service exposure from build-time-only noise so your team fixes what matters first. Griffin AI, Safeguard's autonomous triage engine, correlates this CVE against your live SBOM, cross-references the CVSS/EPSS/KEV signal automatically, and drafts a prioritized remediation plan without a human having to manually chase down where resolve or webpack pulled path-parse in from. Safeguard's continuous SBOM generation and ingest pipeline keeps that dependency graph current as your lockfiles change, so newly introduced or reintroduced vulnerable versions are caught the moment they land rather than at the next scheduled scan. And when remediation is confirmed as needed, Safeguard opens an auto-fix pull request that bumps or overrides path-parse to 1.0.7+ across affected manifests and lockfiles, letting your engineers review and merge a working fix instead of hand-editing dependency trees.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.