Safeguard
Vulnerability Analysis

CVE-2022-21680: ReDoS in marked via block token regexes

CVE-2022-21680: how a ReDoS in marked's block-tokenizer regexes could let attackers freeze Markdown-rendering services, plus affected versions, fix, and mitigation steps.

Aman Khan
AppSec Engineer
7 min read

marked, one of the most widely used Markdown-to-HTML parsers in the JavaScript ecosystem, shipped a Regular Expression Denial of Service (ReDoS) vulnerability tracked as CVE-2022-21680. A specially crafted Markdown input could drive marked's block-level tokenizer regexes into catastrophic backtracking, pinning a CPU core at 100% and freezing the parsing process. For any service that renders untrusted Markdown on the request path — comment systems, README renderers, chat clients, documentation portals, static site generators — that translates directly into a single-request denial-of-service vector.

marked is downloaded tens of millions of times a week and sits behind a huge share of the "render user Markdown to HTML" logic on the web, which is what makes a parser-level ReDoS worth taking seriously even though it doesn't lead to code execution or data exposure. Availability, not confidentiality or integrity, is the impact here — but availability incidents on shared rendering infrastructure can cascade quickly if the vulnerable parser runs synchronously in a request-handling thread or in a Node.js event loop, where one blocked call stalls every other request being served by that process.

What Went Wrong

marked's lexer works by running an ordered list of regular expressions against the remaining input to decide what kind of block or inline token comes next (heading, list item, code fence, link, emphasis, and so on). Several of these rules were written with nested quantifiers and overlapping character classes — patterns that are easy to write, easy to miss in review, and pathological for a regex engine's backtracking algorithm when fed the right adversarial string. With certain constructed sequences, the regex engine's matching time grows exponentially (or high-degree polynomially) with input length rather than linearly, so an input just a few hundred bytes long can take seconds or minutes to evaluate instead of microseconds.

This is the classic ReDoS pattern that has recurred across the Markdown-parser ecosystem — marked, markdown-it, and others have each had their own instances — because Markdown grammars are inherently regex-heavy and full of ambiguous constructs (nested emphasis, link reference definitions, HTML blocks) that tempt authors toward greedy, backtracking-prone patterns. CVE-2022-21680 is one of a cluster of ReDoS advisories fixed in marked around the same release window, reflecting a broader hardening pass the maintainers ran across the tokenizer's block-level rules.

Affected Versions and Components

  • Component: marked npm package (the markedjs/marked project), used both server-side (Node.js) and in browser bundles.
  • Vulnerable versions: Releases prior to 4.0.10.
  • Fixed version: 4.0.10 and later.
  • Advisory: GitHub Security Advisory GHSA-5v2h-r2cx-5xgj, assigned CVE-2022-21680.
  • Attack surface: Any code path that calls marked's marked()/Lexer functions on Markdown text that originates from, or is influenced by, an untrusted party — user comments, README/wiki content, chat messages, imported documents, pasted content rendered as a preview, etc. Applications that only render Markdown authored by trusted, internal sources are at much lower practical risk, but transitive exposure is common: marked is pulled in indirectly by editors, static site generators, documentation frameworks, and CMS plugins that many teams don't realize are in their dependency tree.

Because marked is so frequently a transitive dependency rather than a direct one, the more consequential question for most organizations isn't "do we use marked" but "how many of our first- and third-party components pull it in, and at what version." That's the kind of question a manifest-level dependency list can't reliably answer, but a build-time SBOM can.

CVSS, EPSS, and KEV Context

The advisory for this class of marked ReDoS issue was rated in the High severity range under CVSS v3.1, consistent with a network-exploitable, low-complexity, no-authentication, no-user-interaction vulnerability whose impact is confined to availability (a profile that typically scores around 7.5 on the CVSS v3.1 scale for pure ReDoS findings). As with most ReDoS CVEs, there is no confidentiality or integrity impact — the risk is entirely a denial-of-service condition tied to CPU exhaustion during regex evaluation.

CVE-2022-21680 has not been added to CISA's Known Exploited Vulnerabilities (KEV) catalog, and there is no public evidence of active, widespread exploitation in the wild. That's typical for library-level ReDoS bugs: they're real and reproducible, and they can be devastating against a specific unprotected endpoint, but they don't produce the kind of remote-code-execution or credential-theft outcomes that drive KEV listing or high EPSS exploitation-probability scores. Teams should still treat "not KEV-listed" as a statement about historical exploitation evidence, not a statement about exploitability — a working ReDoS payload against an exposed Markdown-rendering endpoint is generally trivial for an attacker to construct and test once the vulnerable regex is known.

Timeline

  • Prior to disclosure: Versions of marked before 4.0.10 shipped block-tokenizer regexes vulnerable to catastrophic backtracking on crafted input.
  • Fix released: The marked maintainers patched the vulnerable regexes and shipped the fix in marked 4.0.10.
  • Public disclosure: The issue was published as GitHub Security Advisory GHSA-5v2h-r2cx-5xgj and assigned CVE-2022-21680, alongside sibling ReDoS advisories fixed in the same release cycle.
  • Downstream propagation: As with most npm ecosystem CVEs, remediation depended on downstream projects bumping their marked dependency (directly or via lockfile updates) and republishing; adoption lagged the actual fix by weeks to months across the long tail of consumers, which is the normal pattern for widely-embedded parsing libraries.

Remediation

  1. Upgrade marked to 4.0.10 or later. This is the complete fix — the vulnerable regex patterns were rewritten to eliminate the backtracking behavior, and no configuration workaround is needed once you're on a patched version.
  2. Audit for transitive exposure. Run npm ls marked (or the equivalent for yarn/pnpm) across your services, and check bundler lockfiles for older marked versions pulled in by documentation tools, static site generators, CMS plugins, or Markdown editors. A single outdated transitive dependency is enough to reintroduce the exposure even if your direct dependency is current.
  3. Pin and verify, don't just bump the range. Semver ranges like ^3.0.0 won't automatically pull in a 4.x fix across a major version boundary. Confirm the resolved version in your lockfile, not just the range in package.json.
  4. Add defense-in-depth around untrusted-input parsing. Regardless of the specific CVE, any code path that runs a regex-heavy parser (Markdown, YAML, or otherwise) against attacker-controlled input benefits from a timeout or worker-thread isolation so a pathological input can't stall the main event loop or request thread indefinitely.
  5. Re-test after upgrade. If your team previously worked around this class of issue with input-length limits or custom sanitization, verify those mitigations don't mask a still-vulnerable transitive copy of marked elsewhere in the dependency graph, and consider removing brittle workarounds once the real fix is confirmed in place.

How Safeguard Helps

CVE-2022-21680 is a good illustration of why dependency risk management can't stop at direct package.json entries. marked is exactly the kind of package that gets pulled in two or three layers deep — through a Markdown editor, a docs generator, or a CMS plugin — where teams have no first-hand awareness they're exposed at all.

Safeguard's software supply chain security platform is built to close that visibility gap and act on it:

  • Continuous SBOM generation gives you an accurate, build-time inventory of every direct and transitive dependency across your services, so a vulnerable marked version buried three layers deep in a docs tool shows up the same way a direct dependency would.
  • Real-time vulnerability correlation matches your live SBOMs against CVE feeds like this one as soon as they're published, flagging affected components before an attacker gets there first — rather than waiting for a quarterly dependency audit.
  • Risk-prioritized remediation guidance helps teams tell the difference between "marked is present but only renders trusted internal content" and "marked is on the untrusted-input path of a public-facing endpoint," so engineering time goes to the fixes that actually reduce exploitable risk.
  • Policy-driven build gates can block merges or deployments that would introduce a known-vulnerable version of a dependency like marked, turning a CVE advisory into an automated control instead of a manual checklist item.

For a vulnerability class like ReDoS — low in confidentiality/integrity impact but capable of taking down a service with a single crafted request — the highest-leverage move is simply knowing where the vulnerable code lives before it ships. Safeguard is built to make that answer available continuously, not just when someone remembers to ask.

Never miss an update

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