fix: Handle GitLab Flavored Markdown (#11930)

* fix: Handle GitLab Flavored Markdown

* PR feedback

* Harden HTML comment stripping against overlapping patterns

Loop the replacement until stable to avoid CodeQL's incomplete
multi-character sanitization alert — a single pass could leave
`<!--` residue for inputs like `<!<!-- x -->-- -->`.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-04-18 10:53:50 -04:00
committed by GitHub
parent 600108bc43
commit 60562f4f6a
3 changed files with 213 additions and 3 deletions
+56
View File
@@ -277,6 +277,62 @@ export class GitLabUtils {
return palette[projectId % 7];
}
/**
* Sanitizes GitLab-flavored markdown to standard markdown compatible with
* our editor. Strips or converts GitLab-specific syntax that would otherwise
* render as raw text in previews.
*
* Note: This is for display purposes only and is not a security boundary.
* Do not rely on this to sanitize untrusted HTML.
*
* @param text - the markdown text to sanitize.
* @returns the sanitized text, or null if input is null/undefined.
*/
public static sanitizeGitLabMarkdown(
text: string | null | undefined
): string | null {
if (!text) {
return null;
}
// Strip HTML comments repeatedly in case of overlapping patterns like
// `<!<!-- x -->-- -->` that would leave `<!--` after a single pass.
let result = text;
let prev: string;
do {
prev = result;
result = result.replace(/<!--[\s\S]*?-->/g, "");
} while (result !== prev);
return (
result
// YAML front matter
.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "")
// Collapsible sections: extract inner content
.replace(
/<details>\s*<summary>([\s\S]*?)<\/summary>([\s\S]*?)<\/details>/gi,
"**$1**\n$2"
)
// TOC markers
.replace(/\[\[_TOC_\]\]/g, "")
.replace(/^\[TOC\]$/gm, "")
// Inline diffs
.replace(/\{\+([\s\S]*?)\+\}/g, "$1")
.replace(/\[-([\s\S]*?)-\]/g, "~~$1~~")
// Multiline blockquotes
.replace(/^>>>\s*$/gm, "")
// Footnote definitions
.replace(/^\[\^[^\]]+\]:\s+.*$/gm, "")
// Footnote references
.replace(/\[\^([^\]]+)\]/g, "")
// Include directives
.replace(/^::include\{[^}]*\}$/gm, "")
// Clean up excessive blank lines left by removals
.replace(/\n{3,}/g, "\n\n")
.trim() || null
);
}
/**
* Returns the color associated with a given visibility level.
*