Skip to content

fix(comark): make renderMarkdown round-trips safe against injection - #376

Open
atinux wants to merge 6 commits into
mainfrom
fix/roundtrip-safety
Open

fix(comark): make renderMarkdown round-trips safe against injection#376
atinux wants to merge 6 commits into
mainfrom
fix/roundtrip-safety

Conversation

@atinux

@atinux atinux commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

What

Three serializer hardening fixes (one commit each): pickFence() chooses code fences that the content cannot close (pre, mermaid, YAML props blocks), comarkAttributes keeps double quotes inside values inert, and text-node escaping now covers the Comark markers ::/{.

Why

A security scan found that inert content could become live structure after a documented parse → renderMarkdown → re-parse cycle: code containing a ~~~ line or mermaid content containing ``` broke out of its fence into live ::alert markup, an attribute value with a double quote injected new attributes on re-parse, and text holding `::alert{...}` (from escaped or entity-encoded sources) re-parsed into a real component invocation. The quoting fix prefers single quotes because the props parser does not unescape backslashes.

Known limitation: block math ($$…$$) has no alternative delimiter, so math content containing $$ still cannot round-trip — out of scope here.


🤖 Prepared by an AI agent (OpenCode) from a security-audit findings list; commits are signed by the repository owner's key.

atinux added 4 commits August 21, 2026 11:43
pre, mermaid, and YAML attribute blocks picked a fixed 3-backtick fence
(switching to tildes only when the content contained backticks). Code
containing a ~~~ line closed the fence early on re-parse, turning inert
code into live document structure (e.g. ::alert components) — and the
same applied to mermaid content and YAML props blocks.

Add pickFence(): scan the content for the longest line-start run of
each fence character and emit the shorter side, one character longer
than any run present. Also stop growing mermaid content by a blank
line per round trip.
comarkAttributes emitted string values as key="value" with no
escaping, so a value containing a double quote closed the attribute on
re-parse and the remainder became new attacker-chosen attributes (or a
binding resolving frontmatter data). The props parser does not unescape
backslashes, so prefer single quotes when the value has none; fall back
to \"-escaping when both quote kinds are present.
A text node holding ::alert{...} (from an escaped or entity-encoded
source) was emitted verbatim by renderMarkdown, so a re-parse turned
literal text into a live component invocation; a bare :: line inside a
block component also closed the fence early.

escapeLeadingBlock now escapes lines starting with ':', and
escapeInline escapes ':' that can start an inline component (after
whitespace/start/*/_/[, before a name character) and '{' that opens an
attribute block.
@atinux
atinux requested a review from farnabaz as a code owner August 21, 2026 09:45
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
comark Ready Ready Preview Aug 21, 2026 1:31pm
comark-json-render Ready Ready Preview Aug 21, 2026 1:31pm
comark-nextjs Ready Ready Preview Aug 21, 2026 1:31pm
comark-nuxt Ready Ready Preview Aug 21, 2026 1:31pm
comark-svelte Ready Ready Preview Aug 21, 2026 1:31pm
comark-sveltekit Ready Ready Preview Aug 21, 2026 1:31pm
comark-twoslash Ready Ready Preview Aug 21, 2026 1:31pm
comark-vue Ready Ready Preview Aug 21, 2026 1:31pm

@pkg-pr-new

pkg-pr-new Bot commented Aug 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

comark

npm i https://pkg.pr.new/comark@376

@comark/angular

npm i https://pkg.pr.new/@comark/angular@376

@comark/ansi

npm i https://pkg.pr.new/@comark/ansi@376

@comark/html

npm i https://pkg.pr.new/@comark/html@376

@comark/nuxt

npm i https://pkg.pr.new/@comark/nuxt@376

@comark/react

npm i https://pkg.pr.new/@comark/react@376

@comark/svelte

npm i https://pkg.pr.new/@comark/svelte@376

@comark/vue

npm i https://pkg.pr.new/@comark/vue@376

commit: ebb1226

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant