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
markedversion, 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.0or18.0.1in 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 aroundmarkedprocesses 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
markeddependency to18.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
markedis 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.mdfile 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.0or18.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.jsonwhilepackage-lock.json,pnpm-lock.yaml,yarn.lock, a workspace lockfile, an SBOM, or a bundled artifact still resolvesmarked 18.0.0or18.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.
Related recipes
- Source code attack surface map
- Source code injection sink audit
- OWASP Top 10 2026 audit
- SAST finding triage and fix