BLOG-45 fix: XSS html issue
All checks were successful
Frontend CI / build (push) Successful in 1m3s

This commit is contained in:
SquidSpirit 2025-07-24 12:29:14 +08:00
parent e4807cac7a
commit 06b8c8fa0b
4 changed files with 31 additions and 2 deletions

View File

@ -24,6 +24,7 @@
"@tailwindcss/typography": "^0.5.15", "@tailwindcss/typography": "^0.5.15",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.0",
"@types/markdown-it": "^14.1.2", "@types/markdown-it": "^14.1.2",
"dompurify": "^3.2.6",
"eslint": "^9.18.0", "eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1", "eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^3.0.0", "eslint-plugin-svelte": "^3.0.0",

View File

@ -38,6 +38,9 @@ importers:
'@types/markdown-it': '@types/markdown-it':
specifier: ^14.1.2 specifier: ^14.1.2
version: 14.1.2 version: 14.1.2
dompurify:
specifier: ^3.2.6
version: 3.2.6
eslint: eslint:
specifier: ^9.18.0 specifier: ^9.18.0
version: 9.31.0(jiti@2.4.2) version: 9.31.0(jiti@2.4.2)
@ -640,6 +643,9 @@ packages:
'@types/resolve@1.20.2': '@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
'@typescript-eslint/eslint-plugin@8.38.0': '@typescript-eslint/eslint-plugin@8.38.0':
resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -809,6 +815,9 @@ packages:
devalue@5.1.1: devalue@5.1.1:
resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==}
dompurify@3.2.6:
resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==}
enhanced-resolve@5.18.2: enhanced-resolve@5.18.2:
resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@ -1997,6 +2006,9 @@ snapshots:
'@types/resolve@1.20.2': {} '@types/resolve@1.20.2': {}
'@types/trusted-types@2.0.7':
optional: true
'@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3)': '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3)':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.1 '@eslint-community/regexpp': 4.12.1
@ -2175,6 +2187,10 @@ snapshots:
devalue@5.1.1: {} devalue@5.1.1: {}
dompurify@3.2.6:
optionalDependencies:
'@types/trusted-types': 2.0.7
enhanced-resolve@5.18.2: enhanced-resolve@5.18.2:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11

View File

@ -0,0 +1,11 @@
<script lang="ts">
/* eslint-disable svelte/no-at-html-tags */
import DOMPurify from 'dompurify';
const { html }: { html: string } = $props();
const sanitizedHtml = $derived(DOMPurify.sanitize(html));
</script>
{@html sanitizedHtml}

View File

@ -3,6 +3,7 @@
import PostContentHeader from '$lib/post/framework/ui/PostContentHeader.svelte'; import PostContentHeader from '$lib/post/framework/ui/PostContentHeader.svelte';
import { getContext, onMount } from 'svelte'; import { getContext, onMount } from 'svelte';
import markdownit from 'markdown-it'; import markdownit from 'markdown-it';
import SafeHtml from '$lib/common/framework/ui/SafeHtml.svelte';
const { id }: { id: number } = $props(); const { id }: { id: number } = $props();
@ -15,12 +16,12 @@
onMount(() => postBloc.dispatch({ event: PostEventType.PostLoadedEvent, id: id })); onMount(() => postBloc.dispatch({ event: PostEventType.PostLoadedEvent, id: id }));
</script> </script>
<article class="prose container pb-10"> <article class="container prose pb-10">
{#if state.data} {#if state.data}
<PostContentHeader postInfo={state.data.info} /> <PostContentHeader postInfo={state.data.info} />
<div class="max-w-3xl"> <div class="max-w-3xl">
<hr /> <hr />
{@html parsedContent} <SafeHtml html={parsedContent} />
</div> </div>
{/if} {/if}
</article> </article>