diff --git a/src/views/wiki.ts b/src/views/wiki.ts
index ad528a9..c3e44f1 100644
--- a/src/views/wiki.ts
+++ b/src/views/wiki.ts
@@ -1,4 +1,5 @@
import { canEdit } from "../lib/access.ts";
+import { escapeHtml } from "../lib/html.ts";
import { t } from "../lib/i18n/index.ts";
import { newNoteUrl, noteUrl } from "../lib/urls.ts";
import type { WikiIdentity } from "../lib/wiki-identity.ts";
@@ -18,13 +19,13 @@ export function wikiPage(
.map(
(n) => `
${msg.wiki.notes}
${newNoteButton}
diff --git a/tests/views/wiki.test.ts b/tests/views/wiki.test.ts
new file mode 100644
index 0000000..3516056
--- /dev/null
+++ b/tests/views/wiki.test.ts
@@ -0,0 +1,37 @@
+import { describe, expect, test } from "bun:test";
+import { wikiPage } from "../../src/views/wiki.ts";
+
+// Targeted exception to the "views only check status/content-type" rule: XSS
+// inertness is a behavioral property worth asserting directly. The wiki-home
+// fallback view renders wiki.name / note titles / language from records that
+// may originate on a third-party PDS, so they must be escaped.
+const baseWiki = { name: "Safe Wiki", handle: "alice.test", slug: "test" };
+
+describe("wikiPage XSS escaping", () => {
+ test("escapes a malicious wiki name", () => {
+ const html = wikiPage(
+ { ...baseWiki, name: "

" },
+ { locale: "en" },
+ );
+ expect(html).not.toContain("
;)
{
+ const html = wikiPage(baseWiki, {
+ locale: "en",
+ sidebarNotes: [{ slug: "n", title: "" }],
+ });
+ expect(html).not.toContain("");
+ expect(html).toContain("<script>");
+ });
+
+ test("escapes a malicious wiki language badge", () => {
+ const html = wikiPage(
+ baseWiki,
+ { locale: "en" },
+ 'en">',
+ );
+ expect(html).not.toContain("");
+ });
+});