fix: Escape backslashes in table-cell code & math fences

CodeQL flagged incomplete string escaping: escaping pipes as \| without
escaping pre-existing backslashes leaves the encoding ambiguous. Escape the
backslash (the escape character) and pipe together in a single pass so cell
content cannot break out of the column.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-06-03 07:44:49 -04:00
parent 4da4cd7f6a
commit aadf47f2d7
3 changed files with 14 additions and 7 deletions
+8 -3
View File
@@ -668,7 +668,9 @@ This is a [test paragraph](https://example.net)`,
{
type: "code_fence",
attrs: { language: "abap" },
content: [{ type: "text", text: "line 1\nline 2" }],
content: [
{ type: "text", text: "a | b\nc \\ d\nline 2" },
],
},
],
},
@@ -683,8 +685,11 @@ This is a [test paragraph](https://example.net)`,
includeTitle: false,
});
// Code fences inside tables should use <br> tags rather than literal
// newlines that would break the table row structure.
expect(result).toContain("```abap<br>line 1<br>line 2<br>```");
// newlines that would break the table row structure, with pipes and
// backslashes escaped so the content cannot break out of the column.
expect(result).toContain(
"```abap<br>a \\| b<br>c \\\\ d<br>line 2<br>```"
);
// The fence content must not introduce raw newlines inside the table.
expect(result).not.toMatch(/```abap\n/);
});
+3 -2
View File
@@ -695,10 +695,11 @@ export default class CodeFence extends Node<CodeFenceOptions> {
toMarkdown(state: MarkdownSerializerState, node: ProsemirrorNode) {
// Inside table cells literal newlines break the row structure, so encode
// the fence on a single line using <br> for line breaks and escape pipes.
// the fence on a single line using <br> for line breaks. Backslashes and
// pipes are escaped so the cell content cannot break out of the column.
if (state.inTable) {
const code = node.textContent
.replace(/\|/g, "\\|")
.replace(/[\\|]/g, "\\$&")
.replace(/\n/g, "<br>");
state.write(
"```" + (node.attrs.language || "") + "<br>" + code + "<br>```"
+3 -2
View File
@@ -47,10 +47,11 @@ export default class MathBlock extends Node {
toMarkdown(state: MarkdownSerializerState, node: ProsemirrorNode) {
// Inside table cells literal newlines break the row structure, so encode
// the block on a single line using <br> for line breaks and escape pipes.
// the block on a single line using <br> for line breaks. Backslashes and
// pipes are escaped so the cell content cannot break out of the column.
if (state.inTable) {
const math = node.textContent
.replace(/\|/g, "\\|")
.replace(/[\\|]/g, "\\$&")
.replace(/\n/g, "<br>");
state.write("$$<br>" + math + "<br>$$");
return;