Skip to content

fix: stop an unclosed inline raw tag from unescaping later blocks - #4130

Open
thebriangao wants to merge 1 commit into
markedjs:masterfrom
thebriangao:fix/unclosed-inline-raw-tag
Open

thebriangao wants to merge 1 commit into
markedjs:masterfrom
thebriangao:fix/unclosed-inline-raw-tag

Conversation

@thebriangao

Copy link
Copy Markdown

Marked version: master (6a57018, 18.1.0)

Markdown flavor: CommonMark|GitHub Flavored Markdown

Description

I couldn't find an existing issue for this.

An inline <pre>, <code>, <kbd> or <script> tag sets lexer.state.inRawBlock, which makes inlineText emit text without escaping it. Nothing resets the flag between blocks. One unclosed tag therefore turns off escaping for every later block in the document: paragraphs, headings, list items and table cells.

Expectation

Wrap the shortcut in a <kbd> tag.

Then loop while i<n and stop.

Done & dusted.
<p>Wrap the shortcut in a <kbd> tag.</p>
<p>Then loop while i&lt;n and stop.</p>
<p>Done &amp; dusted.</p>

This is what the commonmark and markdown-it dev-dependencies both produce.

Result

<p>Wrap the shortcut in a <kbd> tag.</p>
<p>Then loop while i<n and stop.</p>
<p>Done & dusted.</p>

In a browser the second paragraph renders as just "Then loop while i". The unescaped <n and stop.</p is parsed as an element, and the rest of the line disappears. This matters for apps that render LLM/agent output with marked, which I do (with DOMPurify afterwards), because that prose often names a tag without backticks.

Fix

Reset inRawBlock before each block's inline run in Lexer.lex(). Raw text within a block is unchanged, for example <code>a & b</code>, including when it spans a line break. The new spec covers both cases. This follows the same approach as the outerInRawBlock restore in #4051, which fixed this leak for discarded link text.

Verification

  • New spec: test/specs/new/unclosed_inline_raw_tag uses renderExact, because the differ normalizes entities. It fails on master and passes with the fix. npm test passes in full.
  • Differential run: I compared old and new builds over 86k parses: every CommonMark/GFM example, the new/original specs, docs/, and 20k fuzzed documents, each under 4 option sets.
    • Every changed output came from an input containing an inline raw tag.
    • Every changed output is identical to the old one after entity-decoding, so only escaping changed, never structure.
  • One existing input changes: CommonMark example 170 under pedantic: true. It is a <script> spanning a blank line, which marked already splits with </p>\n<p>. Its second paragraph is now escaped as well.
  • Performance: benchmarked on a 77 KiB document with interleaved runs, the difference stays within ±2% noise.

inLink has the same problem: an unclosed <a …> stops autolinking in later blocks. Its effect is milder, so I left it out to keep this PR focused. I'm happy to add it if you'd like.

AI disclosure: the bug was found, and this fix and its verification were prepared, with Claude Code (AI-assisted).

Contributor

  • Test(s) exist to ensure functionality and minimize regression (if no tests added, list tests covering this PR); or,
  • no tests required for this PR.
  • If submitting new feature, it has been documented in the appropriate places.

Committer

In most cases, this should be a different person than the contributor.

🤖 Generated with Claude Code

An inline <pre>, <code>, <kbd> or <script> tag sets lexer.state.inRawBlock,
which makes inlineText emit text without escaping it. The flag was never
reset between blocks, so one unclosed tag left the text of every later
paragraph, heading, list item and table cell unescaped: `i<n & m` came out
as `i<n & m` instead of `i&lt;n &amp; m`, and a browser then parses the
`<n` as an element and drops the text after it.

Reset the flag before each block's inline run. Raw text within a block
is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 10, 2026

Copy link
Copy Markdown

@thebriangao is attempting to deploy a commit to the MarkedJS Team on Vercel.

A member of the Team first needs to authorize it.

@vercel

vercel Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
marked-website Ready Ready Preview Oct 10, 2026 9:56pm UTC

Request Review

@UziTech UziTech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

This branch was successfully deployed

1 active deployment
Preview — d1ed182d Deployed Oct 10, 2026 by vercel[bot]
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.

2 participants