From 0e93bf92b547d3ca9dfcec6736fd691ef9fd885c Mon Sep 17 00:00:00 2001 From: FuturMix Date: Sun, 14 Jun 2026 12:20:10 +0800 Subject: [PATCH] fix(docs): sanitize markdown HTML output to prevent XSS (fixes #63) --- apps/logicsrc-web/src/app/docs/[slug]/page.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/logicsrc-web/src/app/docs/[slug]/page.tsx b/apps/logicsrc-web/src/app/docs/[slug]/page.tsx index be2fbf7..a335b74 100644 --- a/apps/logicsrc-web/src/app/docs/[slug]/page.tsx +++ b/apps/logicsrc-web/src/app/docs/[slug]/page.tsx @@ -3,6 +3,7 @@ import { notFound } from "next/navigation"; import type { ReactNode } from "react"; import type { Metadata } from "next"; import { marked } from "marked"; +import sanitizeHtml from "sanitize-html"; import { DOC_SLUGS, docExcerpt, docTitle, readDoc } from "@/lib/docs"; import { SiteShell } from "@/components/site-shell"; @@ -37,7 +38,16 @@ export default async function DocPage({ const md = readDoc(slug); if (!md) notFound(); - const html = await marked.parse(md); + const rawHtml = await marked.parse(md); + const html = sanitizeHtml(rawHtml, { + allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img", "h1", "h2", "h3"]), + allowedAttributes: { + ...sanitizeHtml.defaults.allowedAttributes, + img: ["src", "alt", "width", "height"], + a: ["href", "name", "target", "rel"], + code: ["class"], + }, + }); return (