diff --git a/ui/src/components/markdown.ts b/ui/src/components/markdown.ts
index 2ffe3fac072d..4589d40adbb0 100644
--- a/ui/src/components/markdown.ts
+++ b/ui/src/components/markdown.ts
@@ -1266,39 +1266,16 @@ md.core.ruler.after("linkify", "file-links", (state) => {
// accessibility when the item contains links (MDN warns against anchors inside labels).
md.use(markdownItTaskLists, { enabled: false, label: false });
-// Mark the html_inline token inside task-list items as trusted so the
-// html_inline override lets it through. With label: false, the plugin generates
-// only a single token per item.
-// We identify task-list items by the class="task-list-item" the plugin sets.
+// The plugin inserts its checkbox as the first inline child. Trust only that
+// generated token so later user-authored HTML remains escaped.
md.core.ruler.after("github-task-lists", "task-list-allowlist", (state) => {
- const tokens = state.tokens;
- for (let i = 2; i < tokens.length; i++) {
- const token = tokens[i];
- const paragraph = tokens[i - 1];
- const listItem = tokens[i - 2];
- if (!token || !paragraph || !listItem) {
+ for (const [index, listItem] of state.tokens.entries()) {
+ if (listItem.type !== "list_item_open" || listItem.attrGet("class") !== "task-list-item") {
continue;
}
- if (token.type !== "inline" || !token.children) {
- continue;
- }
- if (paragraph.type !== "paragraph_open") {
- continue;
- }
- if (listItem.type !== "list_item_open") {
- continue;
- }
- const cls = listItem.attrGet("class") ?? "";
- if (!cls.includes("task-list-item")) {
- continue;
- }
- // Only trust the checkbox token from the plugin, not other user-supplied HTML.
- // The plugin inserts an at the start; user HTML elsewhere must stay escaped.
- for (const child of token.children) {
- if (child.type === "html_inline" && /^ {
};
md.renderer.rules.html_inline = (tokens, idx) => {
const token = tokens[idx];
- if (!token) {
- return "";
- }
- if (token.meta?.taskListPlugin === true) {
- return token.content;
- }
- return escapeHtml(token.content);
+ return token?.meta?.taskListPlugin === true ? token.content : escapeHtml(token?.content ?? "");
};
md.renderer.rules.code_inline = (tokens, idx, options, env, self) => {