security cleanup, fix turnstile

This commit is contained in:
2026-05-28 16:48:06 -04:00
parent b7187721db
commit d48bbc0fc3
14 changed files with 318 additions and 189 deletions

View File

@@ -1,5 +1,42 @@
import { onMount } from "solid-js";
/**
* Sanitize Mermaid SVG output by removing dangerous elements and attributes.
* Prevents stored XSS via malicious Mermaid diagram code.
*/
function sanitizeMermaidSvg(svgString: string): string {
const parser = new DOMParser();
const doc = parser.parseFromString(svgString, "text/html");
// Remove dangerous elements
doc.querySelectorAll("script, iframe, object, embed, form, link, meta, base").forEach((el) => {
el.remove();
});
// Remove event handlers and dangerous attributes from all elements
doc.querySelectorAll("[on*], [href*='javascript:'], [style*='expression(']").forEach((el) => {
const attrs = Array.from(el.attributes);
attrs.forEach((attr) => {
if (
attr.name.startsWith("on") ||
attr.name === "href" ||
attr.name === "style"
) {
const value = attr.value;
if (
attr.name.startsWith("on") ||
value.includes("javascript:") ||
value.includes("expression(")
) {
el.removeAttribute(attr.name);
}
}
});
});
return doc.body.innerHTML;
}
export default function MermaidRenderer() {
onMount(async () => {
const mermaidPres = document.querySelectorAll('pre[data-type="mermaid"]');
@@ -12,7 +49,7 @@ export default function MermaidRenderer() {
mermaid.initialize({
startOnLoad: false,
theme: "dark",
securityLevel: "loose",
securityLevel: "strict",
fontFamily: "monospace",
themeVariables: {
darkMode: true,
@@ -38,7 +75,7 @@ export default function MermaidRenderer() {
const wrapper = document.createElement("div");
wrapper.className = "mermaid-rendered";
wrapper.innerHTML = svg;
wrapper.innerHTML = sanitizeMermaidSvg(svg);
pre.replaceWith(wrapper);
} catch (err) {
console.error("Failed to render mermaid diagram:", err);