Repository navigation
fix(security): stop the MDX code-span scan at a block boundary - #1122
Merged
Merged
Conversation
blankInlineSpans() searched for a closing backtick run across newlines and stopped only at a blank line. CommonMark parses inlines one leaf block at a time, so an unclosed backtick at the end of one block cannot pair with a backtick in the next; pairing them blanked every construct in between and the payload reached the published site unscanned. Closes #1121 Signed-off-by: sec-check <sec-check@hive.kubestellar.io>
Contributor
Author
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "sec-check" agent while Hive policy required a human checkpoint for that agent. Non-outreach agents are held at ACMM L3–L5; the Hive will keep the |
This was referenced Oct 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security Fix
findActiveContent()(scripts/lib/mdx-active-content.mjs) is the gate that keepsimported third-party Markdown from shipping live MDX into the published site. Before
scanning, it blanks inline code spans; the closer search crossed newlines and stopped
only at a blank line.
CommonMark parses inlines one leaf block at a time, and a blank line is not the only
thing that ends a block. A list item, an ATX heading, a block quote, a thematic break
or an HTML block interrupts a paragraph with no blank line present, so an unclosed
backtick at the end of one block cannot pair with a backtick in the next one.
blankInlineSpans()paired them anyway and blanked everything between, and thepayload was never scanned:
returned
[]onmain, while both the referencecommonmarkparser andmicromark(the engine Docusaurus/MDX uses) render the element live.
What changed
Both changes are in
scripts/lib/mdx-active-content.mjs:BLOCK_INTERRUPT_PATTERNS/startsNewBlock()— the line beginnings thatstart a new block: blank line, ATX heading, block quote, bullet and ordered list
item, thematic break, and line-initial HTML block.
blankInlineSpans()stops the closer search at the first line that begins a newblock instead of at a blank line.
Two deliberate choices, both documented in the source:
blankFences()has already replaced everyfence line with spaces by the time this runs, so a real fence is matched as a blank
line. Adding a fence pattern would false-positive on
```<iframe>`, a line thereal parser resolves into an ordinary code span (verified against micromark).
<matches, thoughCommonMark only lets
1.and HTML block types 1-6 interrupt a paragraph. Stoppingearly can only leave more text scanned — the fail-closed direction this module
states as its rule.
Verification
lines, payload
<iframe src="https://evil.test">), comparing "rendered live bymicromark" against "reported by
findActiveContent" — 66/66 missed before thischange, 0/66 after.
ordered item, block quote, line-initial HTML block and thematic break; one pinning
that a genuine lazy paragraph continuation still forms a span and reports nothing.
node --test tests/mdx-active-content.test.mjs— 29/29 pass.npm run test:unit:coverage:check— exits 0;scripts/lib/mdx-active-content.mjsand
tests/mdx-active-content.test.mjsboth at 100.00% lines / 100.00% regions.npx prettier --checkclean on both changed files.Scope
Touches only
scripts/lib/mdx-active-content.mjsandtests/mdx-active-content.test.mjs; no workflow file is involved. Disjoint from everyopen hold-gated PR: #1090 is
scripts/lib/svg-active-content.mjs, #1112 ispackage.json/package-lock.json, and #1104/#1110/#1113/#1114/#1117/#1120 are allunder
tests/e2e*.Closes #1121
Filed by sec-check agent (ACMM L4/L5 — hold-gated mode). Hold-gated: human review required.
— hive: agent=sec-check backend=copilot model=claude-opus-5 copilot=1.0.88