Skip to content

fix(reports): grow the markdown fence past backticks in the message - #1306

Merged
Chemaclass merged 2 commits into
mainfrom
fix/md-report-fence-injection
Aug 17, 2026
Merged

fix(reports): grow the markdown fence past backticks in the message#1306
Chemaclass merged 2 commits into
mainfrom
fix/md-report-fence-injection

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1305

--report-md fences each failure message unescaped, because a fence renders its contents literally — true only while the fence is longer than any run of backticks inside it. A hook printing a bare fence closed the block early, so the text after it rendered as prose and the trailing fence opened a new, unterminated one. Every later section of the report was swallowed.

That report is auto-appended to $GITHUB_STEP_SUMMARY, so it corrupts the Actions job summary — the page the report exists to be read on.

💡 Changes

  • The opening fence grows past the longest run of backticks present, which is how CommonMark closes a fence. Fork-free and terminating: the message is finite, and testing containment rather than equality finds the longest run, since a message holding four backticks contains three too
  • The regression test asserts the property, not the implementation: the longest backtick-only line is the delimiter, and it must appear an even number of times. Counting every backtick-only line would call the fixed document broken, since the message keeps its own inner fence

🔍 Notes

The diff-rendered case survived by luck — assert_same wraps changed lines as [-...-], which is not a bare delimiter. Undiffed messages (hook failures, source failures) reach the report intact, which is why this showed up in a hook fixture.

HTML was swept at the same time and is clean: <script> is escaped and there are no stray ampersands. The Markdown summary table has no message column, so no | injection either.

The failure message is fenced unescaped because a fence renders its
contents literally -- true only while the fence is longer than any run of
backticks inside it. A hook printing a bare fence closed the block early:
the text after it rendered as prose and the trailing fence opened a new,
unterminated one, swallowing every later section of a report that is
appended to $GITHUB_STEP_SUMMARY.

CommonMark closes a fence only with one at least as long, so the opener
grows past the longest run present. Fork-free and terminating: the message
is finite, and testing containment rather than equality finds the longest
run, since a message holding four backticks contains three too.

The diffed case survived by luck -- assert_same wraps changed lines as
[-...-], which is not a bare delimiter. Undiffed messages (hook and source
failures) reach the report intact.

Closes #1305
@Chemaclass Chemaclass added the bug Something isn't working label Aug 17, 2026
@Chemaclass Chemaclass self-assigned this Aug 17, 2026
@Chemaclass
Chemaclass merged commit f930e47 into main Aug 17, 2026
37 checks passed
@Chemaclass
Chemaclass deleted the fix/md-report-fence-injection branch August 17, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant