Files
multica/server/internal/sanitize/html_test.go
Jiayuan Zhang 6c5879215d fix: sanitize markdown rendering in comments and shared renderers (#679)
* fix: sanitize markdown rendering in comments and shared renderers

Add rehype-sanitize to both ReadonlyContent and Markdown components so
that raw HTML parsed by rehype-raw is sanitized against a strict
allowlist before reaching the DOM. On the backend, add a bluemonday
sanitization pass when creating and updating comments to strip
dangerous tags as defense-in-depth.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add mention:// protocol to sanitize allowlist and validate file card URLs

- Add mention:// to rehype-sanitize protocols.href in both ReadonlyContent
  and Markdown so @mention links survive sanitization
- Validate data-href on file cards to only allow http(s) URLs, blocking
  javascript: and data: schemes in both frontend click handler and backend
  bluemonday policy
- Narrow class attribute allowlist to specific elements (code, div, span, pre)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 03:44:30 +08:00

94 lines
2.4 KiB
Go

package sanitize
import (
"testing"
)
func TestHTML(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{
name: "plain text",
input: "hello world",
want: "hello world",
},
{
name: "safe markdown",
input: "**bold** and *italic*",
want: "**bold** and *italic*",
},
{
name: "script tag stripped",
input: `<script>alert(1)</script>`,
want: "",
},
{
name: "iframe stripped",
input: `<iframe srcdoc="<script>parent.__xss=1</script>"></iframe>`,
want: "",
},
{
name: "img with onerror stripped",
input: `<img src=x onerror="alert(1)">`,
want: `<img src="x">`,
},
{
name: "safe link preserved",
input: `<a href="https://example.com">link</a>`,
want: `<a href="https://example.com" rel="nofollow">link</a>`,
},
{
name: "file card div preserved",
input: `<div data-type="fileCard" data-href="https://cdn.example.com/file.pdf" data-filename="report.pdf"></div>`,
want: `<div data-type="fileCard" data-href="https://cdn.example.com/file.pdf" data-filename="report.pdf"></div>`,
},
{
name: "object tag stripped",
input: `<object data="evil.swf"></object>`,
want: "",
},
{
name: "embed tag stripped",
input: `<embed src="evil.swf">`,
want: "",
},
{
name: "style tag stripped",
input: `<style>body{display:none}</style>`,
want: "",
},
{
name: "mention link preserved",
input: `[@User](mention://member/abc-123)`,
want: `[@User](mention://member/abc-123)`,
},
{
name: "file card with javascript href stripped",
input: `<div data-type="fileCard" data-href="javascript:alert(1)" data-filename="evil.pdf"></div>`,
want: `<div data-type="fileCard" data-filename="evil.pdf"></div>`,
},
{
name: "file card with data URI stripped",
input: `<div data-type="fileCard" data-href="data:text/html,<script>alert(1)</script>" data-filename="x.html"></div>`,
want: `<div data-type="fileCard" data-filename="x.html"></div>`,
},
{
name: "file card with http href preserved",
input: `<div data-type="fileCard" data-href="http://example.com/file.pdf" data-filename="file.pdf"></div>`,
want: `<div data-type="fileCard" data-href="http://example.com/file.pdf" data-filename="file.pdf"></div>`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := HTML(tt.input)
if got != tt.want {
t.Errorf("HTML(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}