fix: address security findings from final review

- Replace regex HTML sanitization with DOMPurify in NoteWidget (XSS fix)
- Remove allow-same-origin from default iframe sandbox in EmbedWidget
- Add URL scheme validation for embed URLs (http/https only)
- Install isomorphic-dompurify dependency
This commit is contained in:
2026-03-24 23:50:37 +03:00
parent 87ed928a3a
commit 5a6002be76
4 changed files with 788 additions and 37 deletions
+10 -12
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { marked } from 'marked';
import DOMPurify from 'isomorphic-dompurify';
interface NoteConfig {
content: string;
@@ -12,7 +13,6 @@
let { config }: Props = $props();
// Configure marked for security
marked.setOptions({
breaks: true,
gfm: true
@@ -20,24 +20,22 @@
const renderedContent = $derived.by(() => {
if (config.format === 'text') {
return config.content
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\n/g, '<br>');
return DOMPurify.sanitize(
config.content
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\n/g, '<br>')
);
}
// Sanitize by stripping script tags and event handlers from markdown output
const raw = marked.parse(config.content, { async: false }) as string;
return raw
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/\s*on\w+\s*=\s*"[^"]*"/gi, '')
.replace(/\s*on\w+\s*=\s*'[^']*'/gi, '');
return DOMPurify.sanitize(raw);
});
</script>
<div class="flex h-full flex-col rounded-xl border border-border bg-card p-4">
<div class="prose prose-sm prose-invert max-w-none flex-1 overflow-auto text-foreground">
<!-- eslint-disable-next-line svelte/no-at-html-tags -- content is sanitized above -->
<!-- eslint-disable-next-line svelte/no-at-html-tags -- sanitized with DOMPurify -->
{@html renderedContent}
</div>
</div>