CVE-2026-41680 - marked tokenizer OOM denial of service

marked versions 18.0.0 and 18.0.1 can recurse until Node.js exhausts memory while parsing a tiny control-character Markdown input. The vulnerable path is especially risky when marked processes untrusted or mixed-trust Markdown for comments, tickets, docs previews, chat messages, model output, webhooks, support content, CMS fields, or generated reports.

This is an availability bug, not an XSS issue. The reviewer-ready fix is still more than a package bump when the parser is on a public request path: upgrade the dependency, prove all controlled lockfiles resolve marked 18.0.2+, and add resource-bounded regression tests or request limits around the app’s real Markdown rendering entry points.

When to use it

Use this recipe when a JavaScript/TypeScript service renders untrusted or mixed-trust Markdown with marked, including comments, tickets, docs previews, chat messages, model output, webhooks, CMS fields, or generated reports. It is designed for source-code remediation, parser resource-bound review, availability testing, and audit evidence that Markdown parsing cannot exhaust server memory.

Inputs

  • marked version, package manifests, lockfiles, Markdown render paths, request limits, worker isolation, and deployment runtime.
  • Source paths that call marked, preprocess Markdown, render previews, cache parsed output, or expose Markdown parsing on public or tenant-facing routes.
  • Regression fixtures for the control-character recursion case, benign Markdown, large inputs, timeout/resource budgets, and expected reject behavior.
  • Boundary evidence: who can submit Markdown, where parsing runs, memory limits, queue/concurrency controls, and observability for parse failures.

Affected versions

Package Vulnerable versions Fixed version
marked 18.0.0, 18.0.1 18.0.2+

Indicator-of-exposure

  • The repository resolves marked 18.0.0 or 18.0.1 in a package lockfile, workspace lockfile, SBOM, generated dependency report, bundled artifact, or image layer.
  • marked.parse, marked.lexer, marked.parser, new marked.Marked(), or a wrapper around marked processes user-controlled or model-controlled Markdown.
  • Markdown rendering runs in the same Node.js process as an API, queue worker, webhook handler, chatbot, MCP server, docs preview, support tool, or admin UI without a parser timeout, input size cap, worker isolation, or rate limit.
  • The app accepts unauthenticated or low-trust Markdown input and renders it synchronously before authentication, authorization, tenant checks, or queue admission limits.

Quick checks:

rg -n "marked|marked\\.parse|marked\\.lexer|marked\\.parser|new Marked|markdown|mdx|remark|user content|model output|chat" .
npm ls marked
pnpm why marked
yarn why marked

Windows:

rg -n 'marked|marked\.parse|marked\.lexer|marked\.parser|new Marked|markdown|mdx|remark|user content|model output|chat' .
npm ls marked
pnpm why marked
yarn why marked

Do not send vendor proof-of-concept inputs to production or public preview endpoints. Any parser regression fixture must run locally, under a timeout, in a process that does not hold secrets or tenant data.

Remediation strategy

  • Upgrade every controlled marked dependency to 18.0.2+.
  • Refresh package locks, generated dependency reports, SBOMs, bundles, and image layers that include marked.
  • Trace the application’s real Markdown render entry points, not just direct dependency declarations. Include framework wrappers, preview components, queue workers, chatbot renderers, email templates, support admin views, and documentation build steps.
  • Add resource-bounded regression tests that parse the vendor-documented control-character fixture locally and assert the renderer returns or rejects within a strict timeout without crashing the test process.
  • Add or verify request-level containment for untrusted Markdown: input size caps, parser worker isolation, server-side timeout, queue admission limit, rate limit, and circuit breaker for repeated parse failures.
  • If upgrade is temporarily blocked, route untrusted Markdown rendering through a worker with memory and CPU limits, disable live preview for untrusted authors, or render high-risk content as plain text until marked is fixed.

The prompt

You are remediating CVE-2026-41680 / GHSA-6v9c-7cg6-27q7, the `marked`
tokenizer recursion denial-of-service issue in versions 18.0.0 and 18.0.1.
Produce exactly one output:

- A reviewer-ready PR/change request that upgrades `marked` to 18.0.2+,
  refreshes generated artifacts, verifies every untrusted Markdown render path,
  adds resource-bounded regression tests, and documents availability controls,
  or
- `TRIAGE.md` if this repository does not control an affected `marked`
  dependency or untrusted Markdown rendering path.

## Rules

- Scope only CVE-2026-41680 / GHSA-6v9c-7cg6-27q7 and directly related
  Markdown parser availability controls.
- Do not send proof-of-concept inputs to production, shared preview
  environments, third-party services, or public endpoints.
- Treat cookies, tokens, prompts, tenant data, support content, private docs,
  chat logs, and generated reports as sensitive.
- Do not remove Markdown sanitization, authentication, authorization, tenant
  checks, logging, or tests to silence the finding.
- Do not auto-merge.

## Steps

1. Inventory every controlled Node.js package graph: manifests, lockfiles,
   workspaces, Dockerfiles, bundles, SBOMs, generated dependency reports,
   vendored code, serverless functions, docs build images, and deployment
   artifacts.
2. Determine every resolved `marked` version. A target is vulnerable if it
   resolves to `18.0.0` or `18.0.1`.
3. Search for Markdown parser entry points: `marked.parse`, `marked.lexer`,
   `marked.parser`, `new Marked`, framework wrappers, preview components,
   docs renderers, support/admin views, chatbot renderers, email template
   renderers, queue workers, and model-output render paths.
4. Classify exposure for each render path: build-time trusted docs, admin-only
   trusted authoring, authenticated user content, unauthenticated public
   content, webhook-controlled content, model-controlled content, queue worker,
   or tenant-crossing support surface.
5. If this repository only references `marked` in documentation, examples, or
   externally owned services, stop with `TRIAGE.md` listing checked files and
   the owner of the affected runtime.
6. Upgrade all controlled `marked` resolutions to `18.0.2+`. Refresh
   lockfiles, generated dependency output, SBOMs, bundles, images, and
   deployment manifests.
7. Add dependency guards so lockfile updates reject `marked 18.0.0` and
   `18.0.1`.
8. Add safe local regression tests:
   - use the vendor-documented minimal control-character fixture;
   - execute the parser in a worker, child process, or test harness with a
     strict timeout and memory cap;
   - assert the app's real render helper returns, rejects, or times out safely;
   - do not run the fixture against production services or privileged browser
     sessions.
9. Add or verify availability controls around untrusted Markdown paths:
   - input size caps;
   - parser timeouts;
   - worker isolation for expensive parsing;
   - request or queue rate limits;
   - circuit breakers and safe error responses for repeated parse failures.
10. Add a PR body section named `CVE-2026-41680 operator actions` that states:
    - `marked` versions before and after;
    - every Markdown input surface reviewed;
    - which surfaces accept unauthenticated, tenant-crossing, webhook, model,
      or low-trust input;
    - what timeout, size, worker, queue, or rate-limit controls are present;
    - which validation commands passed.
11. Run available validation: package install, lockfile integrity,
    dependency guard test, parser regression tests, unit tests, frontend tests,
    build, lint/typecheck, image build, SBOM refresh, and dependency/security
    scans.
12. Use PR title:
    `fix(sec): remediate CVE-2026-41680 in marked rendering`.

## Stop conditions

- No controlled dependency graph resolves `marked 18.0.0` or `18.0.1`.
- The repository only processes trusted build-time Markdown and has no
  vulnerable runtime package resolution.
- The only affected Markdown rendering service is externally owned; document
  the owner and required fixed version in `TRIAGE.md`.
- Meaningful verification would require crashing production, public preview
  systems, shared customer environments, or a process holding secrets.
- Validation fails for unrelated pre-existing reasons; document those failures
  instead of broadening scope.

Output contract

  • A reviewer-ready PR or change request that upgrades marked, proves all lockfiles resolve fixed versions, adds resource-bounded parser tests, and documents runtime limits.
  • Or a TRIAGE.md file that lists inspected files, owner, observed version, Markdown render boundary, request exposure, required fix, and residual risk.
  • The output must include exact validation commands and must not run memory exhaustion tests against production or include customer Markdown content.

Verification - what the reviewer looks for

  • No repository-controlled lockfile, SBOM, generated report, bundle, or image resolves marked 18.0.0 or 18.0.1.
  • Tests exercise the real Markdown rendering helper or service path, not only a direct library call in isolation.
  • Regression tests run the vendor fixture under timeout and memory controls, so a failed test cannot crash the main test runner or leak secrets.
  • Untrusted Markdown surfaces have an explicit size, timeout, worker, queue, or rate-limit control.
  • Operator notes identify any unauthenticated, tenant-crossing, webhook, chatbot, model-output, support, or admin render paths.

Watch for

  • Updating package.json while package-lock.json, pnpm-lock.yaml, yarn.lock, a workspace lockfile, an SBOM, or a bundled artifact still resolves marked 18.0.0 or 18.0.1.
  • Testing only trusted documentation builds while a public comment, chat, or support preview path still uses the vulnerable parser.
  • Adding the proof-of-concept fixture to an integration test that can hit a shared preview or production endpoint.
  • Assuming authentication alone is enough when any low-privilege user can repeatedly crash the Node.js process.
  • Forgetting model-output and agent-generated Markdown renderers, which may process attacker-influenced content even when no direct user Markdown field exists.

References