diff --git a/apps/server/src/services/html_sanitizer.spec.ts b/apps/server/src/services/html_sanitizer.spec.ts index dfbba8fd71..6af366a329 100644 --- a/apps/server/src/services/html_sanitizer.spec.ts +++ b/apps/server/src/services/html_sanitizer.spec.ts @@ -50,4 +50,26 @@ describe("sanitize", () => { `; expect(html_sanitizer.sanitize(dirty)).toBe(clean); }); + + describe("bookmark anchors", () => { + it("preserves id attribute on empty tags (CKEditor bookmarks)", () => { + const dirty = ``; + expect(html_sanitizer.sanitize(dirty)).toBe(dirty); + }); + + it("preserves id attribute on tags with bookmark class", () => { + const dirty = ``; + expect(html_sanitizer.sanitize(dirty)).toBe(dirty); + }); + + it("strips id attribute from non-anchor tags to prevent DOM clobbering", () => { + const dirty = `
`;
+ expect(html_sanitizer.sanitize(dirty)).toBe(`
`);
+ });
+ });
});
diff --git a/apps/server/src/services/html_sanitizer.ts b/apps/server/src/services/html_sanitizer.ts
index f304dcf150..76262c2a32 100644
--- a/apps/server/src/services/html_sanitizer.ts
+++ b/apps/server/src/services/html_sanitizer.ts
@@ -42,6 +42,7 @@ function sanitize(dirtyHtml: string) {
allowedTags: allowedTags as string[],
allowedAttributes: {
"*": ["class", "style", "title", "src", "href", "hash", "disabled", "align", "alt", "center", "data-*"],
+ a: ["id"], // CKEditor bookmark anchors use
input: ["type", "checked"],
img: ["width", "height"],
code: [ "spellcheck" ]